#include "wx/wxprec.h"
#include <locale.h>
#include <ctype.h>
#include <stdlib.h>
#ifdef HAVE_LANGINFO_H
#include <langinfo.h>
#endif

#include "wx/fontmap.h"
#include "wx/file.h"
#include "wx/filename.h"
#include "wx/tokenzr.h"
#include "wx/fontmap.h"
#include "wx/encconv.h"
#include "wx/ptr_scpd.h"
#include "wx/apptrait.h"
#include "wx/stdpaths.h"

typedef wxUint8 size_t8;
typedef wxUint32 size_t32;

const size_t32 MSGCATALOG_MAGIC    = 0x950412de;
const size_t32 MSGCATALOG_MAGIC_SW = 0xde120495;
static const size_t LEN_LANG = 2;
static const size_t LEN_SUBLANG = 2;
static const size_t LEN_FULL = LEN_LANG + 1 + LEN_SUBLANG;

#define TRACE_I18N _T("i18n")

#ifdef __WXDEBUG__

class NoTransErr {
  public:
    NoTransErr() { ms_suppressCount++; }
    ~NoTransErr() { ms_suppressCount--;  }

    static bool Suppress() { return ms_suppressCount > 0; }

  private:
    static size_t ms_suppressCount;
};

size_t NoTransErr::ms_suppressCount = 0;

#else

class NoTransErr {
  public:
    NoTransErr() { }
    ~NoTransErr() { }
};

#endif

static wxLocale *wxSetLocale( wxLocale *pLocale );
static inline wxString ExtractLang( const wxString& langFull ) {
  return langFull.Left( LEN_LANG );
}

static inline wxString ExtractNotLang( const wxString& langFull ) {
  return langFull.Mid( LEN_LANG );
}


class wxPluralFormsToken {
  public:
    enum Type {
      T_ERROR, T_EOF, T_NUMBER, T_N, T_PLURAL, T_NPLURALS, T_EQUAL, T_ASSIGN,
      T_GREATER, T_GREATER_OR_EQUAL, T_LESS, T_LESS_OR_EQUAL,
      T_REMINDER, T_NOT_EQUAL,
      T_LOGICAL_AND, T_LOGICAL_OR, T_QUESTION, T_COLON, T_SEMICOLON,
      T_LEFT_BRACKET, T_RIGHT_BRACKET
    };
    Type type() const { return m_type; }
    void setType( Type type ) { m_type = type; }

    typedef int Number;
    Number number() const { return m_number; }
    void setNumber( Number num ) { m_number = num; }
  private:
    Type m_type;
    Number m_number;
};

class wxPluralFormsScanner {
  public:
    wxPluralFormsScanner( const char* s );
    const wxPluralFormsToken& token() const { return m_token; }
    bool nextToken();
  private:
    const char* m_s;
    wxPluralFormsToken m_token;
};

wxPluralFormsScanner::wxPluralFormsScanner( const char* s ) : m_s( s ) {
  nextToken();
}

bool wxPluralFormsScanner::nextToken() {
  wxPluralFormsToken::Type type = wxPluralFormsToken::T_ERROR;
  while( isspace( ( unsigned char ) *m_s ) ) {
    ++m_s;
  }
  if( *m_s == 0 ) {
    type = wxPluralFormsToken::T_EOF;
  } else if( isdigit( ( unsigned char ) *m_s ) ) {
    wxPluralFormsToken::Number number = *m_s++ - '0';
    while( isdigit( ( unsigned char ) *m_s ) ) {
      number = number * 10 + ( *m_s++ - '0' );
    }
    m_token.setNumber( number );
    type = wxPluralFormsToken::T_NUMBER;
  } else if( isalpha( ( unsigned char ) *m_s ) ) {
    const char* begin = m_s++;
    while( isalnum( ( unsigned char ) *m_s ) ) {
      ++m_s;
    }
    size_t size = m_s - begin;
    if( size == 1 && memcmp( begin, "n", size ) == 0 ) {
      type = wxPluralFormsToken::T_N;
    } else if( size == 6 && memcmp( begin, "plural", size ) == 0 ) {
      type = wxPluralFormsToken::T_PLURAL;
    } else if( size == 8 && memcmp( begin, "nplurals", size ) == 0 ) {
      type = wxPluralFormsToken::T_NPLURALS;
    }
  } else if( *m_s == '=' ) {
    ++m_s;
    if( *m_s == '=' ) {
      ++m_s;
      type = wxPluralFormsToken::T_EQUAL;
    } else
    { type = wxPluralFormsToken::T_ASSIGN; }
  } else if( *m_s == '>' ) {
    ++m_s;
    if( *m_s == '=' ) {
      ++m_s;
      type = wxPluralFormsToken::T_GREATER_OR_EQUAL;
    } else
    { type = wxPluralFormsToken::T_GREATER; }
  } else if( *m_s == '<' ) {
    ++m_s;
    if( *m_s == '=' ) {
      ++m_s;
      type = wxPluralFormsToken::T_LESS_OR_EQUAL;
    } else
    { type = wxPluralFormsToken::T_LESS; }
  } else if( *m_s == '%' ) {
    ++m_s;
    type = wxPluralFormsToken::T_REMINDER;
  } else if( *m_s == '!' && m_s[1] == '=' ) {
    m_s += 2;
    type = wxPluralFormsToken::T_NOT_EQUAL;
  } else if( *m_s == '&' && m_s[1] == '&' ) {
    m_s += 2;
    type = wxPluralFormsToken::T_LOGICAL_AND;
  } else if( *m_s == '|' && m_s[1] == '|' ) {
    m_s += 2;
    type = wxPluralFormsToken::T_LOGICAL_OR;
  } else if( *m_s == '?' ) {
    ++m_s;
    type = wxPluralFormsToken::T_QUESTION;
  } else if( *m_s == ':' ) {
    ++m_s;
    type = wxPluralFormsToken::T_COLON;
  } else if( *m_s == ';' ) {
    ++m_s;
    type = wxPluralFormsToken::T_SEMICOLON;
  } else if( *m_s == '(' ) {
    ++m_s;
    type = wxPluralFormsToken::T_LEFT_BRACKET;
  } else if( *m_s == ')' ) {
    ++m_s;
    type = wxPluralFormsToken::T_RIGHT_BRACKET;
  }
  m_token.setType( type );
  return type != wxPluralFormsToken::T_ERROR;
}

class wxPluralFormsNode;

class wxPluralFormsNodePtr {
  public:
    wxPluralFormsNodePtr( wxPluralFormsNode *p = NULL ) : m_p( p ) {}
    ~wxPluralFormsNodePtr();
    wxPluralFormsNode& operator*() const { return *m_p; }
    wxPluralFormsNode* operator->() const { return m_p; }
    wxPluralFormsNode* get() const { return m_p; }
    wxPluralFormsNode* release();
    void reset( wxPluralFormsNode *p );

  private:
    wxPluralFormsNode *m_p;
};

class wxPluralFormsNode {
  public:
    wxPluralFormsNode( const wxPluralFormsToken& token ) : m_token( token ) {}
    const wxPluralFormsToken& token() const { return m_token; }
    const wxPluralFormsNode* node( size_t i ) const
    { return m_nodes[i].get(); }
    void setNode( size_t i, wxPluralFormsNode* n );
    wxPluralFormsNode* releaseNode( size_t i );
    wxPluralFormsToken::Number evaluate( wxPluralFormsToken::Number n ) const;

  private:
    wxPluralFormsToken m_token;
    wxPluralFormsNodePtr m_nodes[3];
};

wxPluralFormsNodePtr::~wxPluralFormsNodePtr() {
  delete m_p;
}
wxPluralFormsNode* wxPluralFormsNodePtr::release() {
  wxPluralFormsNode *p = m_p;
  m_p = NULL;
  return p;
}
void wxPluralFormsNodePtr::reset( wxPluralFormsNode *p ) {
  if( p != m_p ) {
    delete m_p;
    m_p = p;
  }
}


void wxPluralFormsNode::setNode( size_t i, wxPluralFormsNode* n ) {
  m_nodes[i].reset( n );
}

wxPluralFormsNode*  wxPluralFormsNode::releaseNode( size_t i ) {
  return m_nodes[i].release();
}

wxPluralFormsToken::Number
wxPluralFormsNode::evaluate( wxPluralFormsToken::Number n ) const {
  switch( token().type() ) {
    case wxPluralFormsToken::T_NUMBER:
      return token().number();
    case wxPluralFormsToken::T_N:
      return n;
    case wxPluralFormsToken::T_EQUAL:
      return node( 0 )->evaluate( n ) == node( 1 )->evaluate( n );
    case wxPluralFormsToken::T_NOT_EQUAL:
      return node( 0 )->evaluate( n ) != node( 1 )->evaluate( n );
    case wxPluralFormsToken::T_GREATER:
      return node( 0 )->evaluate( n ) > node( 1 )->evaluate( n );
    case wxPluralFormsToken::T_GREATER_OR_EQUAL:
      return node( 0 )->evaluate( n ) >= node( 1 )->evaluate( n );
    case wxPluralFormsToken::T_LESS:
      return node( 0 )->evaluate( n ) < node( 1 )->evaluate( n );
    case wxPluralFormsToken::T_LESS_OR_EQUAL:
      return node( 0 )->evaluate( n ) <= node( 1 )->evaluate( n );
    case wxPluralFormsToken::T_REMINDER: {
      wxPluralFormsToken::Number number = node( 1 )->evaluate( n );
      if( number != 0 ) {
        return node( 0 )->evaluate( n ) % number;
      } else
      { return 0; }
    }
    case wxPluralFormsToken::T_LOGICAL_AND:
      return node( 0 )->evaluate( n ) && node( 1 )->evaluate( n );
    case wxPluralFormsToken::T_LOGICAL_OR:
      return node( 0 )->evaluate( n ) || node( 1 )->evaluate( n );
    case wxPluralFormsToken::T_QUESTION:
      return node( 0 )->evaluate( n )
             ? node( 1 )->evaluate( n )
             : node( 2 )->evaluate( n );
    default:
      return 0;
  }
}

class wxPluralFormsCalculator {
  public:
    wxPluralFormsCalculator() : m_nplurals( 0 ), m_plural( 0 ) {}
    int evaluate( int n ) const;
    static wxPluralFormsCalculator* make( const char* s = 0 );

    ~wxPluralFormsCalculator() {}

    void  init( wxPluralFormsToken::Number nplurals, wxPluralFormsNode* plural );

  private:
    wxPluralFormsToken::Number m_nplurals;
    wxPluralFormsNodePtr m_plural;
};

wxDEFINE_SCOPED_PTR_TYPE( wxPluralFormsCalculator )

void wxPluralFormsCalculator::init( wxPluralFormsToken::Number nplurals, wxPluralFormsNode* plural ) {
  m_nplurals = nplurals;
  m_plural.reset( plural );
}

int wxPluralFormsCalculator::evaluate( int n ) const {
  if( m_plural.get() == 0 ) {
    return 0;
  }
  wxPluralFormsToken::Number number = m_plural->evaluate( n );
  if( number < 0 || number > m_nplurals ) {
    return 0;
  }
  return number;
}


class wxPluralFormsParser {
  public:
    wxPluralFormsParser( wxPluralFormsScanner& scanner ) : m_scanner( scanner ) {}
    bool parse( wxPluralFormsCalculator& rCalculator );

  private:
    wxPluralFormsNode* parsePlural();

    wxPluralFormsScanner& m_scanner;
    const wxPluralFormsToken& token() const;
    bool nextToken();

    wxPluralFormsNode* expression();
    wxPluralFormsNode* logicalOrExpression();
    wxPluralFormsNode* logicalAndExpression();
    wxPluralFormsNode* equalityExpression();
    wxPluralFormsNode* multiplicativeExpression();
    wxPluralFormsNode* relationalExpression();
    wxPluralFormsNode* pmExpression();
};

bool wxPluralFormsParser::parse( wxPluralFormsCalculator& rCalculator ) {
  if( token().type() != wxPluralFormsToken::T_NPLURALS ) {
    return false;
  }
  if( !nextToken() ) {
    return false;
  }
  if( token().type() != wxPluralFormsToken::T_ASSIGN ) {
    return false;
  }
  if( !nextToken() ) {
    return false;
  }
  if( token().type() != wxPluralFormsToken::T_NUMBER ) {
    return false;
  }
  wxPluralFormsToken::Number nplurals = token().number();
  if( !nextToken() ) {
    return false;
  }
  if( token().type() != wxPluralFormsToken::T_SEMICOLON ) {
    return false;
  }
  if( !nextToken() ) {
    return false;
  }
  if( token().type() != wxPluralFormsToken::T_PLURAL ) {
    return false;
  }
  if( !nextToken() ) {
    return false;
  }
  if( token().type() != wxPluralFormsToken::T_ASSIGN ) {
    return false;
  }
  if( !nextToken() ) {
    return false;
  }
  wxPluralFormsNode* plural = parsePlural();
  if( plural == 0 ) {
    return false;
  }
  if( token().type() != wxPluralFormsToken::T_SEMICOLON ) {
    return false;
  }
  if( !nextToken() ) {
    return false;
  }
  if( token().type() != wxPluralFormsToken::T_EOF ) {
    return false;
  }
  rCalculator.init( nplurals, plural );
  return true;
}

wxPluralFormsNode* wxPluralFormsParser::parsePlural() {
  wxPluralFormsNode* p = expression();
  if( p == NULL ) {
    return NULL;
  }
  wxPluralFormsNodePtr n( p );
  if( token().type() != wxPluralFormsToken::T_SEMICOLON ) {
    return NULL;
  }
  return n.release();
}

const wxPluralFormsToken& wxPluralFormsParser::token() const {
  return m_scanner.token();
}

bool wxPluralFormsParser::nextToken() {
  if( !m_scanner.nextToken() ) {
    return false;
  }
  return true;
}

wxPluralFormsNode* wxPluralFormsParser::expression() {
  wxPluralFormsNode* p = logicalOrExpression();
  if( p == NULL ) {
    return NULL;
  }
  wxPluralFormsNodePtr n( p );
  if( token().type() == wxPluralFormsToken::T_QUESTION ) {
    wxPluralFormsNodePtr qn( new wxPluralFormsNode( token() ) );
    if( !nextToken() ) {
      return 0;
    }
    p = expression();
    if( p == 0 ) {
      return 0;
    }
    qn->setNode( 1, p );
    if( token().type() != wxPluralFormsToken::T_COLON ) {
      return 0;
    }
    if( !nextToken() ) {
      return 0;
    }
    p = expression();
    if( p == 0 ) {
      return 0;
    }
    qn->setNode( 2, p );
    qn->setNode( 0, n.release() );
    return qn.release();
  }
  return n.release();
}

wxPluralFormsNode*wxPluralFormsParser::logicalOrExpression() {
  wxPluralFormsNode* p = logicalAndExpression();
  if( p == NULL ) {
    return NULL;
  }
  wxPluralFormsNodePtr ln( p );
  if( token().type() == wxPluralFormsToken::T_LOGICAL_OR ) {
    wxPluralFormsNodePtr un( new wxPluralFormsNode( token() ) );
    if( !nextToken() ) {
      return 0;
    }
    p = logicalOrExpression();
    if( p == 0 ) {
      return 0;
    }
    wxPluralFormsNodePtr rn( p );
    if( rn->token().type() == wxPluralFormsToken::T_LOGICAL_OR ) {
      un->setNode( 0, ln.release() );
      un->setNode( 1, rn->releaseNode( 0 ) );
      rn->setNode( 0, un.release() );
      return rn.release();
    }
    un->setNode( 0, ln.release() );
    un->setNode( 1, rn.release() );
    return un.release();
  }
  return ln.release();
}

wxPluralFormsNode* wxPluralFormsParser::logicalAndExpression() {
  wxPluralFormsNode* p = equalityExpression();
  if( p == NULL ) {
    return NULL;
  }
  wxPluralFormsNodePtr ln( p );
  if( token().type() == wxPluralFormsToken::T_LOGICAL_AND ) {
    wxPluralFormsNodePtr un( new wxPluralFormsNode( token() ) );
    if( !nextToken() ) {
      return NULL;
    }
    p = logicalAndExpression();
    if( p == 0 ) {
      return NULL;
    }
    wxPluralFormsNodePtr rn( p );
    if( rn->token().type() == wxPluralFormsToken::T_LOGICAL_AND ) {
      un->setNode( 0, ln.release() );
      un->setNode( 1, rn->releaseNode( 0 ) );
      rn->setNode( 0, un.release() );
      return rn.release();
    }
    un->setNode( 0, ln.release() );
    un->setNode( 1, rn.release() );
    return un.release();
  }
  return ln.release();
}

wxPluralFormsNode* wxPluralFormsParser::equalityExpression() {
  wxPluralFormsNode* p = relationalExpression();
  if( p == NULL ) {
    return NULL;
  }
  wxPluralFormsNodePtr n( p );
  if( token().type() == wxPluralFormsToken::T_EQUAL
      || token().type() == wxPluralFormsToken::T_NOT_EQUAL ) {
    wxPluralFormsNodePtr qn( new wxPluralFormsNode( token() ) );
    if( !nextToken() ) {
      return NULL;
    }
    p = relationalExpression();
    if( p == NULL ) {
      return NULL;
    }
    qn->setNode( 1, p );
    qn->setNode( 0, n.release() );
    return qn.release();
  }
  return n.release();
}

wxPluralFormsNode* wxPluralFormsParser::relationalExpression() {
  wxPluralFormsNode* p = multiplicativeExpression();
  if( p == NULL ) {
    return NULL;
  }
  wxPluralFormsNodePtr n( p );
  if( token().type() == wxPluralFormsToken::T_GREATER
      || token().type() == wxPluralFormsToken::T_LESS
      || token().type() == wxPluralFormsToken::T_GREATER_OR_EQUAL
      || token().type() == wxPluralFormsToken::T_LESS_OR_EQUAL ) {
    wxPluralFormsNodePtr qn( new wxPluralFormsNode( token() ) );
    if( !nextToken() ) {
      return NULL;
    }
    p = multiplicativeExpression();
    if( p == NULL ) {
      return NULL;
    }
    qn->setNode( 1, p );
    qn->setNode( 0, n.release() );
    return qn.release();
  }
  return n.release();
}

wxPluralFormsNode* wxPluralFormsParser::multiplicativeExpression() {
  wxPluralFormsNode* p = pmExpression();
  if( p == NULL ) {
    return NULL;
  }
  wxPluralFormsNodePtr n( p );
  if( token().type() == wxPluralFormsToken::T_REMINDER ) {
    wxPluralFormsNodePtr qn( new wxPluralFormsNode( token() ) );
    if( !nextToken() ) {
      return NULL;
    }
    p = pmExpression();
    if( p == NULL ) {
      return NULL;
    }
    qn->setNode( 1, p );
    qn->setNode( 0, n.release() );
    return qn.release();
  }
  return n.release();
}

wxPluralFormsNode* wxPluralFormsParser::pmExpression() {
  wxPluralFormsNodePtr n;
  if( token().type() == wxPluralFormsToken::T_N
      || token().type() == wxPluralFormsToken::T_NUMBER ) {
    n.reset( new wxPluralFormsNode( token() ) );
    if( !nextToken() ) {
      return NULL;
    }
  } else if( token().type() == wxPluralFormsToken::T_LEFT_BRACKET ) {
    if( !nextToken() ) {
      return NULL;
    }
    wxPluralFormsNode* p = expression();
    if( p == NULL ) {
      return NULL;
    }
    n.reset( p );
    if( token().type() != wxPluralFormsToken::T_RIGHT_BRACKET ) {
      return NULL;
    }
    if( !nextToken() ) {
      return NULL;
    }
  } else
  { return NULL; }
  return n.release();
}

wxPluralFormsCalculator* wxPluralFormsCalculator::make( const char* s ) {
  wxPluralFormsCalculatorPtr calculator( new wxPluralFormsCalculator );
  if( s != NULL ) {
    wxPluralFormsScanner scanner( s );
    wxPluralFormsParser p( scanner );
    if( !p.parse( *calculator ) ) {
      return NULL;
    }
  }
  return calculator.release();
}

WX_DECLARE_EXPORTED_STRING_HASH_MAP( wxString, wxMessagesHash );

class wxMsgCatalogFile {
  public:

    wxMsgCatalogFile();
    ~wxMsgCatalogFile();


    bool Load( const wxChar *szDirPrefix, const wxChar *szName,
               wxPluralFormsCalculatorPtr& rPluralFormsCalculator );


    void FillHash( wxMessagesHash& hash,
                   const wxString& msgIdCharset,
                   bool convertEncoding ) const;



    wxString GetCharset() const { return m_charset; }

  private:



    struct wxMsgTableEntry {
      size_t32   nLen;
      size_t32   ofsString;
    };


    struct wxMsgCatalogHeader {
      size_t32  magic,
                revision,
                numStrings;
      size_t32  ofsOrigTable,
                ofsTransTable;
      size_t32  nHashSize,
                ofsHashTable;
    };

    size_t8 *m_pData;
    size_t32 m_nSize;
    size_t32          m_numStrings;
    wxMsgTableEntry  *m_pOrigTable,
                     *m_pTransTable;

    wxString m_charset;


    size_t32 Swap( size_t32 ui ) const {
      return m_bSwapped ? ( ui << 24 ) | ( ( ui & 0xff00 ) << 8 ) |
             ( ( ui >> 8 ) & 0xff00 ) | ( ui >> 24 )
             : ui;
    }

    const char *StringAtOfs( wxMsgTableEntry *pTable, size_t32 n ) const {
      const wxMsgTableEntry * const ent = pTable + n;
      size_t32 ofsString = Swap( ent->ofsString );
      if( ofsString + Swap( ent->nLen ) > m_nSize ) {
        return NULL;
      }
      return ( const char * )( m_pData + ofsString );
    }

    bool m_bSwapped;

    DECLARE_NO_COPY_CLASS( wxMsgCatalogFile )
};

class wxMsgCatalog {
  public:
    bool Load( const wxChar *szDirPrefix, const wxChar *szName,
               const wxChar *msgIdCharset = NULL, bool bConvertEncoding = false );


    wxString GetName() const { return m_name; }


    const wxChar *GetString( const wxChar *sz, size_t n = size_t( -1 ) ) const;


    wxMsgCatalog *m_pNext;

  private:
    wxMessagesHash  m_messages;
    wxString        m_name;
    wxPluralFormsCalculatorPtr  m_pluralFormsCalculator;
};

static wxArrayString gs_searchPrefixes;

wxMsgCatalogFile::wxMsgCatalogFile() {
  m_pData = NULL;
  m_nSize = 0;
}

wxMsgCatalogFile::~wxMsgCatalogFile() {
  delete [] m_pData;
}

static
wxString GetMsgCatalogSubdirs( const wxChar *prefix, const wxChar *lang ) {
  wxString pathPrefix;
  pathPrefix << prefix << wxFILE_SEP_PATH << lang;
  wxString searchPath;
  searchPath.reserve( 4 * pathPrefix.length() );
  searchPath << pathPrefix << wxFILE_SEP_PATH << wxT( "LC_MESSAGES" ) << wxPATH_SEP
             << prefix << wxFILE_SEP_PATH << wxPATH_SEP
             << pathPrefix;
  return searchPath;
}

static wxString GetFullSearchPath( const wxChar *lang ) {
  wxArrayString paths;
  paths.reserve( gs_searchPrefixes.size() + 1 );
  size_t n,
         count = gs_searchPrefixes.size();
  for( n = 0; n < count; n++ ) {
    paths.Add( GetMsgCatalogSubdirs( gs_searchPrefixes[n], lang ) );
  }
  #if wxUSE_STDPATHS
  const wxString stdp = wxStandardPaths::Get().
                        GetLocalizedResourcesDir( lang, wxStandardPaths::ResourceCat_Messages );
  if( paths.Index( stdp ) == wxNOT_FOUND ) {
    paths.Add( stdp );
  }
  #endif
  const wxChar *pszLcPath = wxGetenv( wxT( "LC_PATH" ) );
  if( pszLcPath ) {
    const wxString lcp = GetMsgCatalogSubdirs( pszLcPath, lang );
    if( paths.Index( lcp ) == wxNOT_FOUND ) {
      paths.Add( lcp );
    }
  }
  wxString wxp = wxGetInstallPrefix();
  if( !wxp.empty() ) {
    wxp = GetMsgCatalogSubdirs( wxp + _T( "/share/locale" ), lang );
    if( paths.Index( wxp ) == wxNOT_FOUND ) {
      paths.Add( wxp );
    }
  }
  wxString searchPath;
  searchPath.reserve( 500 );
  count = paths.size();
  for( n = 0; n < count; n++ ) {
    searchPath += paths[n];
    if( n != count - 1 ) {
      searchPath += wxPATH_SEP;
    }
  }
  return searchPath;
}

bool wxMsgCatalogFile::Load( const wxChar *szDirPrefix, const wxChar *szName,
                             wxPluralFormsCalculatorPtr& rPluralFormsCalculator ) {
  wxString searchPath;
  wxFontEncoding encSys = wxLocale::GetSystemEncoding();
  if( encSys != wxFONTENCODING_SYSTEM ) {
    wxString fullname( szDirPrefix );
    fullname << _T( '.' ) << wxFontMapperBase::GetEncodingName( encSys );
    searchPath << GetFullSearchPath( fullname ) << wxPATH_SEP;
  }
  searchPath += GetFullSearchPath( szDirPrefix );
  const wxChar *sublocale = wxStrchr( szDirPrefix, wxT( '_' ) );
  if( sublocale ) {
    searchPath << wxPATH_SEP
               << GetFullSearchPath( wxString( szDirPrefix ).
                                     Left( ( size_t )( sublocale - szDirPrefix ) ) );
  }
  NoTransErr noTransErr;
  wxLogVerbose( _( "looking for catalog '%s' in path '%s'." ),
                szName, searchPath.c_str() );
  wxLogTrace( TRACE_I18N, _T( "Looking for \"%s.mo\" in \"%s\"" ), szName, searchPath.c_str() );
  wxFileName fn( szName );
  fn.SetExt( _T( "mo" ) );
  wxString strFullName;
  if( !wxFindFileInPath( &strFullName, searchPath, fn.GetFullPath() ) ) {
    wxLogVerbose( _( "catalog file for domain '%s' not found." ), szName );
    wxLogTrace( TRACE_I18N, _T( "Catalog \"%s.mo\" not found" ), szName );
    return false;
  }
  wxLogVerbose( _( "using catalog '%s' from '%s'." ), szName, strFullName.c_str() );
  wxLogTrace( TRACE_I18N, _T( "Using catalog \"%s\"." ), strFullName.c_str() );
  wxFile fileMsg( strFullName );
  if( !fileMsg.IsOpened() ) {
    return false;
  }
  wxFileOffset lenFile = fileMsg.Length();
  if( lenFile == wxInvalidOffset ) {
    return false;
  }
  size_t nSize = wx_truncate_cast( size_t, lenFile );
  wxASSERT_MSG( nSize == lenFile + size_t( 0 ), _T( "message catalog bigger than 4GB?" ) );
  m_pData = new size_t8[nSize];
  if( fileMsg.Read( m_pData, nSize ) != lenFile ) {
    wxDELETEA( m_pData );
    return false;
  }
  bool bValid = nSize + ( size_t )0 > sizeof( wxMsgCatalogHeader );
  wxMsgCatalogHeader *pHeader = ( wxMsgCatalogHeader * )m_pData;
  if( bValid ) {
    m_bSwapped = pHeader->magic == MSGCATALOG_MAGIC_SW;
    bValid = m_bSwapped || pHeader->magic == MSGCATALOG_MAGIC;
  }
  if( !bValid ) {
    wxLogWarning( _( "'%s' is not a valid message catalog." ), strFullName.c_str() );
    wxDELETEA( m_pData );
    return false;
  }
  m_numStrings  = Swap( pHeader->numStrings );
  m_pOrigTable  = ( wxMsgTableEntry * )( m_pData + Swap( pHeader->ofsOrigTable ) );
  m_pTransTable = ( wxMsgTableEntry * )( m_pData + Swap( pHeader->ofsTransTable ) );
  m_nSize = ( size_t32 )nSize;
  const char* headerData = StringAtOfs( m_pOrigTable, 0 );
  if( headerData && headerData[0] == 0 ) {
    wxString header = wxString::FromAscii( StringAtOfs( m_pTransTable, 0 ) );
    int begin = header.Find( wxT( "Content-Type: text/plain; charset=" ) );
    if( begin != wxNOT_FOUND ) {
      begin += 34;
      size_t end = header.find( '\n', begin );
      if( end != size_t( -1 ) ) {
        m_charset.assign( header, begin, end - begin );
        if( m_charset == wxT( "CHARSET" ) ) {
          m_charset.Clear();
        }
      }
    }
    begin = header.Find( wxT( "Plural-Forms:" ) );
    if( begin != wxNOT_FOUND ) {
      begin += 13;
      size_t end = header.find( '\n', begin );
      if( end != size_t( -1 ) ) {
        wxString pfs( header, begin, end - begin );
        wxPluralFormsCalculator* pCalculator = wxPluralFormsCalculator
                                               ::make( pfs.ToAscii() );
        if( pCalculator != 0 ) {
          rPluralFormsCalculator.reset( pCalculator );
        } else
        { wxLogVerbose( _( "Cannot parse Plural-Forms:'%s'" ), pfs.c_str() ); }
      }
    }
    if( rPluralFormsCalculator.get() == NULL ) {
      rPluralFormsCalculator.reset( wxPluralFormsCalculator::make() );
    }
  }
  return true;
}

void wxMsgCatalogFile::FillHash( wxMessagesHash& hash, const wxString& msgIdCharset, bool convertEncoding ) const {
  convertEncoding = true;
  wxMBConv *inputConv,
           *inputConvPtr = NULL;
  if( convertEncoding && !m_charset.empty() ) {
    inputConvPtr =
      inputConv = new wxCSConv( m_charset );
  } else {
    inputConv = wxConvCurrent;
  }
  wxCSConv *sourceConv = msgIdCharset.empty() || ( msgIdCharset == m_charset ) ? NULL : new wxCSConv( msgIdCharset );
  ( void )convertEncoding;
  for( size_t32 i = 0; i < m_numStrings; i++ ) {
    const char *data = StringAtOfs( m_pOrigTable, i );
    wxString msgid;
    msgid = wxString( data, *inputConv );
    data = StringAtOfs( m_pTransTable, i );
    size_t length = Swap( m_pTransTable[i].nLen );
    size_t offset = 0;
    size_t index = 0;
    while( offset < length ) {
      const char * const str = data + offset;
      wxString msgstr;
      msgstr = wxString( str, *inputConv );
      if( !msgstr.empty() ) {
        hash[index == 0 ? msgid : msgid + wxChar( index )] = msgstr;
      }
      offset += strlen( str ) + 1;
      ++index;
    }
  }
  #if wxUSE_WCHAR_T
  delete sourceConv;
  delete inputConvPtr;
  #endif
}

bool wxMsgCatalog::Load( const wxChar *szDirPrefix, const wxChar *szName,
                         const wxChar *msgIdCharset, bool bConvertEncoding ) {
  wxMsgCatalogFile file;
  m_name = szName;
  if( !file.Load( szDirPrefix, szName, m_pluralFormsCalculator ) ) {
    return false;
  }
  file.FillHash( m_messages, msgIdCharset, bConvertEncoding );
  return true;
}

const wxChar *wxMsgCatalog::GetString( const wxChar *sz, size_t n ) const {
  int index = 0;
  if( n != size_t( -1 ) ) {
    index = m_pluralFormsCalculator->evaluate( n );
  }
  wxMessagesHash::const_iterator i;
  if( index != 0 ) {
    i = m_messages.find( wxString( sz ) + wxChar( index ) );
  } else {
    i = m_messages.find( sz );
  }
  if( i != m_messages.end() ) {
    return i->second.c_str();
  } else {
    return NULL;
  }
}


#include "wx/arrimpl.cpp"
WX_DECLARE_EXPORTED_OBJARRAY( wxLanguageInfo, wxLanguageInfoArray );
WX_DEFINE_OBJARRAY( wxLanguageInfoArray )

wxLanguageInfoArray *wxLocale::ms_languagesDB = NULL;

void wxLocale::CreateLanguagesDB() {
  if( ms_languagesDB == NULL ) {
    ms_languagesDB = new wxLanguageInfoArray;
    InitLanguagesDB();
  }
}

void wxLocale::DestroyLanguagesDB() {
  delete ms_languagesDB;
  ms_languagesDB = NULL;
}


void wxLocale::DoCommonInit() {
  m_pszOldLocale = NULL;
  m_pOldLocale = wxSetLocale( this );
  m_pMsgCat = NULL;
  m_language = wxLANGUAGE_UNKNOWN;
  m_initialized = false;
}

bool wxLocale::Init( const wxChar *szName, const wxChar *szShort, const wxChar *szLocale, bool bLoadDefault, bool bConvertEncoding ) {
  wxASSERT_MSG( !m_initialized, _T( "you can't call wxLocale::Init more than once" ) );
  m_initialized = true;
  m_strLocale = szName;
  m_strShort = szShort;
  m_bConvertEncoding = bConvertEncoding;
  m_language = wxLANGUAGE_UNKNOWN;
  if( szLocale == NULL ) {
    szLocale = szShort;
    wxCHECK_MSG( szLocale, false, _T( "no locale to set in wxLocale::Init()" ) );
  }
  wxMB2WXbuf oldLocale = wxSetlocale( LC_ALL, szLocale );
  if( oldLocale ) {
    m_pszOldLocale = wxStrdup( oldLocale );
  } else
  { m_pszOldLocale = NULL; }
  if( m_pszOldLocale == NULL ) {
    wxLogError( _( "locale '%s' can not be set." ), szLocale );
  }
  if( m_strShort.empty() ) {
    if( szLocale && szLocale[0] ) {
      m_strShort += ( wxChar )wxTolower( szLocale[0] );
      if( szLocale[1] ) {
        m_strShort += ( wxChar )wxTolower( szLocale[1] );
      }
    }
  }
  m_pMsgCat = NULL;
  bool bOk = true;
  if( bLoadDefault ) {
    bOk = AddCatalog( wxT( "wxstd" ) );
    if( bOk ) {
      wxString port( wxPlatformInfo::Get().GetPortIdName() );
      if( !port.empty() ) {
        AddCatalog( port.BeforeFirst( wxT( '/' ) ).MakeLower() );
      }
    }
  }
  return bOk;
}

static wxWCharBuffer wxSetlocaleTryUTF( int c, const wxChar *lc ) {
  wxMB2WXbuf l = wxSetlocale( c, lc );
  if( !l && lc && lc[0] != 0 ) {
    wxString buf( lc );
    wxString buf2;
    buf2 = buf + wxT( ".UTF-8" );
    l = wxSetlocale( c, buf2.c_str() );
    if( !l ) {
      buf2 = buf + wxT( ".utf-8" );
      l = wxSetlocale( c, buf2.c_str() );
    }
    if( !l ) {
      buf2 = buf + wxT( ".UTF8" );
      l = wxSetlocale( c, buf2.c_str() );
    }
  }
  return l;
}

bool wxLocale::Init( int language, int flags ) {
  int lang = language;
  if( lang == wxLANGUAGE_DEFAULT ) {
    lang = GetSystemLanguage();
  }
  if( lang == wxLANGUAGE_UNKNOWN ) {
    return false;
  }
  const wxLanguageInfo *info = GetLanguageInfo( lang );
  if( info == NULL ) {
    wxLogError( wxT( "Unknown language %i." ), lang );
    return false;
  }
  wxString name = info->Description;
  wxString canonical = info->CanonicalName;
  wxString locale;
  if( language != wxLANGUAGE_DEFAULT ) {
    locale = info->CanonicalName;
  }
  wxMB2WXbuf retloc = wxSetlocaleTryUTF( LC_ALL, locale );
  const wxString langOnly = locale.Left( 2 );
  if( !retloc ) {
    retloc = wxSetlocaleTryUTF( LC_ALL, langOnly );
  }
  if( !retloc ) {
    const wxChar **names =
      wxFontMapperBase::GetAllEncodingNames( wxFONTENCODING_UTF8 );
    while( *names ) {
      retloc = wxSetlocale( LC_ALL, locale + _T( '.' ) + *names++ );
      if( retloc ) {
        break;
      }
    }
  }
  if( !retloc ) {
    wxString localeAlt;
    if( langOnly == wxT( "he" ) ) {
      localeAlt = wxT( "iw" ) + locale.Mid( 3 );
    } else if( langOnly == wxT( "id" ) ) {
      localeAlt = wxT( "in" ) + locale.Mid( 3 );
    } else if( langOnly == wxT( "yi" ) ) {
      localeAlt = wxT( "ji" ) + locale.Mid( 3 );
    } else if( langOnly == wxT( "nb" ) ) {
      localeAlt = wxT( "no_NO" );
    } else if( langOnly == wxT( "nn" ) ) {
      localeAlt = wxT( "no_NY" );
    }
    if( !localeAlt.empty() ) {
      retloc = wxSetlocaleTryUTF( LC_ALL, localeAlt );
      if( !retloc ) {
        retloc = wxSetlocaleTryUTF( LC_ALL, localeAlt.Left( 2 ) );
      }
    }
  }
  if( !retloc ) {
    wxLogError( wxT( "Cannot set locale to '%s'." ), locale.c_str() );
    return false;
  }
  wxChar *szLocale = retloc ? wxStrdup( retloc ) : NULL;
  bool ret = Init( name, canonical, szLocale, ( flags & wxLOCALE_LOAD_DEFAULT ) != 0, ( flags & wxLOCALE_CONV_ENCODING ) != 0 );
  free( szLocale );
  if( IsOk() )  {
    m_language = lang;
  }
  return ret;
}



void wxLocale::AddCatalogLookupPathPrefix( const wxString& prefix ) {
  if( gs_searchPrefixes.Index( prefix ) == wxNOT_FOUND ) {
    gs_searchPrefixes.Add( prefix );
  }
}

int wxLocale::GetSystemLanguage() {
  CreateLanguagesDB();
  size_t i = 0,
         count = ms_languagesDB->GetCount();
  wxString langFull;
  if( !wxGetEnv( wxT( "LC_ALL" ), &langFull ) &&
      !wxGetEnv( wxT( "LC_MESSAGES" ), &langFull ) &&
      !wxGetEnv( wxT( "LANG" ), &langFull ) ) {
    return wxLANGUAGE_ENGLISH_US;
  }
  if( langFull == _T( "C" ) || langFull == _T( "POSIX" ) ) {
    return wxLANGUAGE_ENGLISH_US;
  }
  wxString modifier;
  size_t posModifier = langFull.find_first_of( _T( "@" ) );
  if( posModifier != wxString::npos ) {
    modifier = langFull.Mid( posModifier );
  }
  size_t posEndLang = langFull.find_first_of( _T( "@." ) );
  if( posEndLang != wxString::npos ) {
    langFull.Truncate( posEndLang );
  }
  bool justLang = langFull.length() == LEN_LANG;
  if( justLang ||
      ( langFull.length() == LEN_FULL && langFull[LEN_LANG] == wxT( '_' ) ) ) {
    wxString langOrig = ExtractLang( langFull );
    wxString lang;
    if( langOrig == wxT( "iw" ) ) {
      lang = _T( "he" );
    } else if( langOrig == wxT( "in" ) ) {
      lang = wxT( "id" );
    } else if( langOrig == wxT( "ji" ) ) {
      lang = wxT( "yi" );
    } else if( langOrig == wxT( "no_NO" ) ) {
      lang = wxT( "nb_NO" );
    } else if( langOrig == wxT( "no_NY" ) ) {
      lang = wxT( "nn_NO" );
    } else if( langOrig == wxT( "no" ) ) {
      lang = wxT( "nb_NO" );
    } else {
      lang = langOrig;
    }
    if( lang != langOrig ) {
      langFull = lang + ExtractNotLang( langFull );
    }
    if( !modifier.empty() ) {
      wxString langFullWithModifier = langFull + modifier;
      for( i = 0; i < count; i++ ) {
        if( ms_languagesDB->Item( i ).CanonicalName == langFullWithModifier ) {
          break;
        }
      }
    }
    if( modifier.empty() || i == count ) {
      for( i = 0; i < count; i++ ) {
        if( ms_languagesDB->Item( i ).CanonicalName == langFull ) {
          break;
        }
      }
    }
    if( i == count && !justLang ) {
      for( i = 0; i < count; i++ ) {
        if( ms_languagesDB->Item( i ).CanonicalName == lang ) {
          break;
        }
      }
    }
    if( i == count && justLang ) {
      for( i = 0; i < count; i++ ) {
        if( ExtractLang( ms_languagesDB->Item( i ).CanonicalName )
            == langFull ) {
          break;
        }
      }
    }
  } else {
    for( i = 0; i < count; i++ ) {
      if( ms_languagesDB->Item( i ).Description.CmpNoCase( langFull ) == 0 ) {
        break;
      }
    }
  }
  if( i < count ) {
    return ms_languagesDB->Item( i ).Language;
  }
  return wxLANGUAGE_UNKNOWN;
}

wxString wxLocale::GetSystemEncodingName() {
  wxString encname;
  char *oldLocale = strdup( setlocale( LC_CTYPE, NULL ) );
  setlocale( LC_CTYPE, "" );
  const char *alang = nl_langinfo( CODESET );
  setlocale( LC_CTYPE, oldLocale );
  free( oldLocale );
  if( alang ) {
    encname = wxString::FromAscii( alang );
  } else {
    char *lang = getenv( "LC_ALL" );
    char *dot = lang ? strchr( lang, '.' ) : ( char * )NULL;
    if( !dot ) {
      lang = getenv( "LC_CTYPE" );
      if( lang ) {
        dot = strchr( lang, '.' );
      }
    }
    if( !dot ) {
      lang = getenv( "LANG" );
      if( lang ) {
        dot = strchr( lang, '.' );
      }
    }
    if( dot ) {
      encname = wxString::FromAscii( dot + 1 );
    }
  }
  return encname;
}

wxFontEncoding wxLocale::GetSystemEncoding() {
  const wxString encname = GetSystemEncodingName();
  if( !encname.empty() ) {
    wxFontEncoding enc = wxFontMapperBase::GetEncodingFromName( encname );
    if( enc == wxFONTENCODING_DEFAULT ) {
      return wxFONTENCODING_ISO8859_1;
    }
    if( enc != wxFONTENCODING_MAX ) {
      return enc;
    }
  }
  return wxFONTENCODING_SYSTEM;
}

void wxLocale::AddLanguage( const wxLanguageInfo& info ) {
  CreateLanguagesDB();
  ms_languagesDB->Add( info );
}

const wxLanguageInfo *wxLocale::GetLanguageInfo( int lang ) {
  CreateLanguagesDB();
  if( lang == wxLANGUAGE_DEFAULT ) {
    lang = GetSystemLanguage();
  }
  const size_t count = ms_languagesDB->GetCount();
  for( size_t i = 0; i < count; i++ ) {
    if( ms_languagesDB->Item( i ).Language == lang ) {
      wxLanguageInfo *ptr = &ms_languagesDB->Item( i );
      return ptr;
    }
  }
  return NULL;
}

wxString wxLocale::GetLanguageName( int lang ) {
  const wxLanguageInfo *info = GetLanguageInfo( lang );
  if( !info ) {
    return wxEmptyString;
  } else
  { return info->Description; }
}

const wxLanguageInfo *wxLocale::FindLanguageInfo( const wxString& locale ) {
  CreateLanguagesDB();
  const wxLanguageInfo *infoRet = NULL;
  const size_t count = ms_languagesDB->GetCount();
  for( size_t i = 0; i < count; i++ ) {
    const wxLanguageInfo *info = &ms_languagesDB->Item( i );
    if( wxStricmp( locale, info->CanonicalName ) == 0 ||
        wxStricmp( locale, info->Description ) == 0 ) {
      infoRet = info;
      break;
    }
    if( wxStricmp( locale, info->CanonicalName.BeforeFirst( _T( '_' ) ) ) == 0 ) {
      if( !infoRet ) {
        infoRet = info;
      }
    }
  }
  return infoRet;
}

wxString wxLocale::GetSysName() const {
  return wxSetlocale( LC_ALL, NULL );
}

wxLocale::~wxLocale() {
  wxMsgCatalog *pTmpCat;
  while( m_pMsgCat != NULL ) {
    pTmpCat = m_pMsgCat;
    m_pMsgCat = m_pMsgCat->m_pNext;
    delete pTmpCat;
  }
  wxSetLocale( m_pOldLocale );
  wxSetlocale( LC_ALL, m_pszOldLocale );
  free( ( wxChar * )m_pszOldLocale );
}

const wxChar *wxLocale::GetString( const wxChar *szOrigString, const wxChar *szDomain ) const {
  return GetString( szOrigString, szOrigString, size_t( -1 ), szDomain );
}

const wxChar *wxLocale::GetString( const wxChar *szOrigString, const wxChar *szOrigString2, size_t n, const wxChar *szDomain ) const {
  if( wxIsEmpty( szOrigString ) ) {
    return wxEmptyString;
  }
  const wxChar *pszTrans = NULL;
  wxMsgCatalog *pMsgCat;
  if( szDomain != NULL && szDomain[0] ) {
    pMsgCat = FindCatalog( szDomain );
    if( pMsgCat != NULL ) {
      pszTrans = pMsgCat->GetString( szOrigString, n );
    }
  } else {
    for( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) {
      pszTrans = pMsgCat->GetString( szOrigString, n );
      if( pszTrans != NULL )
      { break; }
    }
  }
  if( pszTrans == NULL ) {
    #ifdef __WXDEBUG__
    if( !NoTransErr::Suppress() ) {
      NoTransErr noTransErr;
      wxLogTrace( TRACE_I18N,
                  _T( "string \"%s\"[%ld] not found in %slocale '%s'." ),
                  szOrigString, ( long )n,
                  szDomain ? wxString::Format( _T( "domain '%s' " ), szDomain ).c_str()
                  : _T( "" ),
                  m_strLocale.c_str() );
    }
    #endif
    if( n == size_t( -1 ) ) {
      return szOrigString;
    } else {
      return n == 1 ? szOrigString : szOrigString2;
    }
  }
  return pszTrans;
}

wxString wxLocale::GetHeaderValue( const wxChar* szHeader, const wxChar* szDomain ) const {
  if( wxIsEmpty( szHeader ) ) {
    return wxEmptyString;
  }
  wxChar const * pszTrans = NULL;
  wxMsgCatalog *pMsgCat;
  if( szDomain != NULL ) {
    pMsgCat = FindCatalog( szDomain );
    if( pMsgCat == NULL ) {
      return wxEmptyString;
    }
    pszTrans = pMsgCat->GetString( wxEmptyString, ( size_t ) - 1 );
  } else {
    for( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) {
      pszTrans = pMsgCat->GetString( wxEmptyString, ( size_t ) - 1 );
      if( pszTrans != NULL )
      { break; }
    }
  }
  if( wxIsEmpty( pszTrans ) ) {
    return wxEmptyString;
  }
  wxChar const * pszFound = wxStrstr( pszTrans, szHeader );
  if( pszFound == NULL ) {
    return wxEmptyString;
  }
  pszFound += wxStrlen( szHeader ) + 2 /* ': ' */;
  wxChar const * pszEndLine = wxStrchr( pszFound, wxT( '\n' ) );
  if( pszEndLine == NULL ) {
    pszEndLine = pszFound + wxStrlen( pszFound );
  }
  wxString retVal( pszFound, pszEndLine - pszFound );
  return retVal;
}

wxMsgCatalog *wxLocale::FindCatalog( const wxChar *szDomain ) const {
  wxMsgCatalog *pMsgCat;
  for( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) {
    if( wxStricmp( pMsgCat->GetName(), szDomain ) == 0 ) {
      return pMsgCat;
    }
  }
  return NULL;
}

bool wxLocale::IsAvailable( int lang ) {
  const wxLanguageInfo *info = wxLocale::GetLanguageInfo( lang );
  wxCHECK_MSG( info, false, _T( "invalid language" ) );
  wxMB2WXbuf oldLocale = wxSetlocale( LC_ALL, wxEmptyString );
  wxMB2WXbuf tmp = wxSetlocaleTryUTF( LC_ALL, info->CanonicalName );
  if( !tmp ) {
    tmp = wxSetlocaleTryUTF( LC_ALL, info->CanonicalName.Left( 2 ) );
    if( !tmp ) {
      return false;
    }
  }
  wxSetlocale( LC_ALL, oldLocale );
  return true;
}


bool wxLocale::IsLoaded( const wxChar *szDomain ) const {
  return FindCatalog( szDomain ) != NULL;
}


bool wxLocale::AddCatalog( const wxChar *szDomain ) {
  return AddCatalog( szDomain, wxLANGUAGE_ENGLISH_US, NULL );
}


bool wxLocale::AddCatalog( const wxChar *szDomain,
                           wxLanguage    msgIdLanguage,
                           const wxChar *msgIdCharset )

{
  wxMsgCatalog *pMsgCat = new wxMsgCatalog;
  if( pMsgCat->Load( m_strShort, szDomain, msgIdCharset, m_bConvertEncoding ) ) {
    pMsgCat->m_pNext = m_pMsgCat;
    m_pMsgCat = pMsgCat;
    return true;
  } else {
    delete pMsgCat;
    if( m_language == msgIdLanguage ) {
      return true;
    }
    const wxLanguageInfo *msgIdLangInfo = GetLanguageInfo( msgIdLanguage );
    if( msgIdLangInfo &&
        msgIdLangInfo->CanonicalName.Mid( 0, 2 ) == m_strShort.Mid( 0, 2 ) ) {
      return true;
    }
    return false;
  }
}





#ifdef __WXMSW__

#elif defined(__DARWIN__)

/* static */
wxString wxLocale::GetInfo( wxLocaleInfo index, wxLocaleCategory( cat ) ) {
  CFLocaleRef userLocaleRefRaw;
  if( wxGetLocale() ) {
    userLocaleRefRaw = CFLocaleCreate
                       (
                         kCFAllocatorDefault,
                         wxMacCFStringHolder( wxGetLocale()->GetCanonicalName() )
                       );
  } else
  { userLocaleRefRaw = CFLocaleCopyCurrent(); }
  wxCFRef<CFLocaleRef> userLocaleRef( userLocaleRefRaw );
  CFTypeRef cfstr;
  switch( index ) {
    case wxLOCALE_THOUSANDS_SEP:
      cfstr = CFLocaleGetValue( userLocaleRef, kCFLocaleGroupingSeparator );
      break;
    case wxLOCALE_DECIMAL_POINT:
      cfstr = CFLocaleGetValue( userLocaleRef, kCFLocaleDecimalSeparator );
      break;
    default:
      wxFAIL_MSG( _T( "Unknown locale info" ) );
  }
  wxMacCFStringHolder
  str( CFStringCreateCopy( NULL, static_cast<CFStringRef>( cfstr ) ) );
  return str.AsString();
}
#error mmmmmmmmmmmm

#else

/* static */
wxString wxLocale::GetInfo( wxLocaleInfo index, wxLocaleCategory cat ) {
  struct lconv *locale_info = localeconv();
  switch( cat ) {
    case wxLOCALE_CAT_NUMBER:
      switch( index ) {
        case wxLOCALE_THOUSANDS_SEP:
          return wxString( locale_info->thousands_sep,
                           *wxConvCurrent );
        case wxLOCALE_DECIMAL_POINT:
          return wxString( locale_info->decimal_point,
                           *wxConvCurrent );
        default:
          return wxEmptyString;
      }
    case wxLOCALE_CAT_MONEY:
      switch( index ) {
        case wxLOCALE_THOUSANDS_SEP:
          return wxString( locale_info->mon_thousands_sep,
                           *wxConvCurrent );
        case wxLOCALE_DECIMAL_POINT:
          return wxString( locale_info->mon_decimal_point,
                           *wxConvCurrent );
        default:
          return wxEmptyString;
      }
    default:
      return wxEmptyString;
  }
}

#endif

static wxLocale *g_pLocale = NULL;

wxLocale *wxGetLocale() {
  return g_pLocale;
}

wxLocale *wxSetLocale( wxLocale *pLocale ) {
  wxLocale *pOld = g_pLocale;
  g_pLocale = pLocale;
  return pOld;
}







class wxLocaleModule: public wxModule {
    DECLARE_DYNAMIC_CLASS( wxLocaleModule )
  public:
    wxLocaleModule() {}
    bool OnInit() { return true; }
    void OnExit() { wxLocale::DestroyLanguagesDB(); }
};

IMPLEMENT_DYNAMIC_CLASS( wxLocaleModule, wxModule )














#if !defined(__WIN32__) || defined(__WXMICROWIN__)

#define SETWINLANG(info,lang,sublang)

#else

#define SETWINLANG(info,lang,sublang) \
  info.WinLang = lang, info.WinSublang = sublang;

#ifndef LANG_AFRIKAANS
#define LANG_AFRIKAANS (0)
#endif
#ifndef LANG_ALBANIAN
#define LANG_ALBANIAN (0)
#endif
#ifndef LANG_ARABIC
#define LANG_ARABIC (0)
#endif
#ifndef LANG_ARMENIAN
#define LANG_ARMENIAN (0)
#endif
#ifndef LANG_ASSAMESE
#define LANG_ASSAMESE (0)
#endif
#ifndef LANG_AZERI
#define LANG_AZERI (0)
#endif
#ifndef LANG_BASQUE
#define LANG_BASQUE (0)
#endif
#ifndef LANG_BELARUSIAN
#define LANG_BELARUSIAN (0)
#endif
#ifndef LANG_BENGALI
#define LANG_BENGALI (0)
#endif
#ifndef LANG_BULGARIAN
#define LANG_BULGARIAN (0)
#endif
#ifndef LANG_CATALAN
#define LANG_CATALAN (0)
#endif
#ifndef LANG_CHINESE
#define LANG_CHINESE (0)
#endif
#ifndef LANG_CROATIAN
#define LANG_CROATIAN (0)
#endif
#ifndef LANG_CZECH
#define LANG_CZECH (0)
#endif
#ifndef LANG_DANISH
#define LANG_DANISH (0)
#endif
#ifndef LANG_DUTCH
#define LANG_DUTCH (0)
#endif
#ifndef LANG_ENGLISH
#define LANG_ENGLISH (0)
#endif
#ifndef LANG_ESTONIAN
#define LANG_ESTONIAN (0)
#endif
#ifndef LANG_FAEROESE
#define LANG_FAEROESE (0)
#endif
#ifndef LANG_FARSI
#define LANG_FARSI (0)
#endif
#ifndef LANG_FINNISH
#define LANG_FINNISH (0)
#endif
#ifndef LANG_FRENCH
#define LANG_FRENCH (0)
#endif
#ifndef LANG_GEORGIAN
#define LANG_GEORGIAN (0)
#endif
#ifndef LANG_GERMAN
#define LANG_GERMAN (0)
#endif
#ifndef LANG_GREEK
#define LANG_GREEK (0)
#endif
#ifndef LANG_GUJARATI
#define LANG_GUJARATI (0)
#endif
#ifndef LANG_HEBREW
#define LANG_HEBREW (0)
#endif
#ifndef LANG_HINDI
#define LANG_HINDI (0)
#endif
#ifndef LANG_HUNGARIAN
#define LANG_HUNGARIAN (0)
#endif
#ifndef LANG_ICELANDIC
#define LANG_ICELANDIC (0)
#endif
#ifndef LANG_INDONESIAN
#define LANG_INDONESIAN (0)
#endif
#ifndef LANG_ITALIAN
#define LANG_ITALIAN (0)
#endif
#ifndef LANG_JAPANESE
#define LANG_JAPANESE (0)
#endif
#ifndef LANG_KANNADA
#define LANG_KANNADA (0)
#endif
#ifndef LANG_KASHMIRI
#define LANG_KASHMIRI (0)
#endif
#ifndef LANG_KAZAK
#define LANG_KAZAK (0)
#endif
#ifndef LANG_KONKANI
#define LANG_KONKANI (0)
#endif
#ifndef LANG_KOREAN
#define LANG_KOREAN (0)
#endif
#ifndef LANG_LATVIAN
#define LANG_LATVIAN (0)
#endif
#ifndef LANG_LITHUANIAN
#define LANG_LITHUANIAN (0)
#endif
#ifndef LANG_MACEDONIAN
#define LANG_MACEDONIAN (0)
#endif
#ifndef LANG_MALAY
#define LANG_MALAY (0)
#endif
#ifndef LANG_MALAYALAM
#define LANG_MALAYALAM (0)
#endif
#ifndef LANG_MANIPURI
#define LANG_MANIPURI (0)
#endif
#ifndef LANG_MARATHI
#define LANG_MARATHI (0)
#endif
#ifndef LANG_NEPALI
#define LANG_NEPALI (0)
#endif
#ifndef LANG_NORWEGIAN
#define LANG_NORWEGIAN (0)
#endif
#ifndef LANG_ORIYA
#define LANG_ORIYA (0)
#endif
#ifndef LANG_POLISH
#define LANG_POLISH (0)
#endif
#ifndef LANG_PORTUGUESE
#define LANG_PORTUGUESE (0)
#endif
#ifndef LANG_PUNJABI
#define LANG_PUNJABI (0)
#endif
#ifndef LANG_ROMANIAN
#define LANG_ROMANIAN (0)
#endif
#ifndef LANG_RUSSIAN
#define LANG_RUSSIAN (0)
#endif
#ifndef LANG_SAMI
#define LANG_SAMI (0)
#endif
#ifndef LANG_SANSKRIT
#define LANG_SANSKRIT (0)
#endif
#ifndef LANG_SERBIAN
#define LANG_SERBIAN (0)
#endif
#ifndef LANG_SINDHI
#define LANG_SINDHI (0)
#endif
#ifndef LANG_SLOVAK
#define LANG_SLOVAK (0)
#endif
#ifndef LANG_SLOVENIAN
#define LANG_SLOVENIAN (0)
#endif
#ifndef LANG_SPANISH
#define LANG_SPANISH (0)
#endif
#ifndef LANG_SWAHILI
#define LANG_SWAHILI (0)
#endif
#ifndef LANG_SWEDISH
#define LANG_SWEDISH (0)
#endif
#ifndef LANG_TAMIL
#define LANG_TAMIL (0)
#endif
#ifndef LANG_TATAR
#define LANG_TATAR (0)
#endif
#ifndef LANG_TELUGU
#define LANG_TELUGU (0)
#endif
#ifndef LANG_THAI
#define LANG_THAI (0)
#endif
#ifndef LANG_TURKISH
#define LANG_TURKISH (0)
#endif
#ifndef LANG_UKRAINIAN
#define LANG_UKRAINIAN (0)
#endif
#ifndef LANG_URDU
#define LANG_URDU (0)
#endif
#ifndef LANG_UZBEK
#define LANG_UZBEK (0)
#endif
#ifndef LANG_VALENCIAN
#define LANG_VALENCIAN (0)
#endif
#ifndef LANG_VIETNAMESE
#define LANG_VIETNAMESE (0)
#endif
#ifndef SUBLANG_ARABIC_ALGERIA
#define SUBLANG_ARABIC_ALGERIA SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ARABIC_BAHRAIN
#define SUBLANG_ARABIC_BAHRAIN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ARABIC_EGYPT
#define SUBLANG_ARABIC_EGYPT SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ARABIC_IRAQ
#define SUBLANG_ARABIC_IRAQ SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ARABIC_JORDAN
#define SUBLANG_ARABIC_JORDAN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ARABIC_KUWAIT
#define SUBLANG_ARABIC_KUWAIT SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ARABIC_LEBANON
#define SUBLANG_ARABIC_LEBANON SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ARABIC_LIBYA
#define SUBLANG_ARABIC_LIBYA SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ARABIC_MOROCCO
#define SUBLANG_ARABIC_MOROCCO SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ARABIC_OMAN
#define SUBLANG_ARABIC_OMAN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ARABIC_QATAR
#define SUBLANG_ARABIC_QATAR SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ARABIC_SAUDI_ARABIA
#define SUBLANG_ARABIC_SAUDI_ARABIA SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ARABIC_SYRIA
#define SUBLANG_ARABIC_SYRIA SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ARABIC_TUNISIA
#define SUBLANG_ARABIC_TUNISIA SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ARABIC_UAE
#define SUBLANG_ARABIC_UAE SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ARABIC_YEMEN
#define SUBLANG_ARABIC_YEMEN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_AZERI_CYRILLIC
#define SUBLANG_AZERI_CYRILLIC SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_AZERI_LATIN
#define SUBLANG_AZERI_LATIN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_CHINESE_SIMPLIFIED
#define SUBLANG_CHINESE_SIMPLIFIED SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_CHINESE_TRADITIONAL
#define SUBLANG_CHINESE_TRADITIONAL SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_CHINESE_HONGKONG
#define SUBLANG_CHINESE_HONGKONG SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_CHINESE_MACAU
#define SUBLANG_CHINESE_MACAU SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_CHINESE_SINGAPORE
#define SUBLANG_CHINESE_SINGAPORE SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_DUTCH
#define SUBLANG_DUTCH SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_DUTCH_BELGIAN
#define SUBLANG_DUTCH_BELGIAN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ENGLISH_UK
#define SUBLANG_ENGLISH_UK SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ENGLISH_US
#define SUBLANG_ENGLISH_US SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ENGLISH_AUS
#define SUBLANG_ENGLISH_AUS SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ENGLISH_BELIZE
#define SUBLANG_ENGLISH_BELIZE SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ENGLISH_CAN
#define SUBLANG_ENGLISH_CAN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ENGLISH_CARIBBEAN
#define SUBLANG_ENGLISH_CARIBBEAN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ENGLISH_EIRE
#define SUBLANG_ENGLISH_EIRE SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ENGLISH_JAMAICA
#define SUBLANG_ENGLISH_JAMAICA SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ENGLISH_NZ
#define SUBLANG_ENGLISH_NZ SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ENGLISH_PHILIPPINES
#define SUBLANG_ENGLISH_PHILIPPINES SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ENGLISH_SOUTH_AFRICA
#define SUBLANG_ENGLISH_SOUTH_AFRICA SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ENGLISH_TRINIDAD
#define SUBLANG_ENGLISH_TRINIDAD SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ENGLISH_ZIMBABWE
#define SUBLANG_ENGLISH_ZIMBABWE SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_FRENCH
#define SUBLANG_FRENCH SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_FRENCH_BELGIAN
#define SUBLANG_FRENCH_BELGIAN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_FRENCH_CANADIAN
#define SUBLANG_FRENCH_CANADIAN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_FRENCH_LUXEMBOURG
#define SUBLANG_FRENCH_LUXEMBOURG SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_FRENCH_MONACO
#define SUBLANG_FRENCH_MONACO SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_FRENCH_SWISS
#define SUBLANG_FRENCH_SWISS SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_GERMAN
#define SUBLANG_GERMAN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_GERMAN_AUSTRIAN
#define SUBLANG_GERMAN_AUSTRIAN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_GERMAN_LIECHTENSTEIN
#define SUBLANG_GERMAN_LIECHTENSTEIN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_GERMAN_LUXEMBOURG
#define SUBLANG_GERMAN_LUXEMBOURG SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_GERMAN_SWISS
#define SUBLANG_GERMAN_SWISS SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ITALIAN
#define SUBLANG_ITALIAN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_ITALIAN_SWISS
#define SUBLANG_ITALIAN_SWISS SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_KASHMIRI_INDIA
#define SUBLANG_KASHMIRI_INDIA SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_KOREAN
#define SUBLANG_KOREAN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_LITHUANIAN
#define SUBLANG_LITHUANIAN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_MALAY_BRUNEI_DARUSSALAM
#define SUBLANG_MALAY_BRUNEI_DARUSSALAM SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_MALAY_MALAYSIA
#define SUBLANG_MALAY_MALAYSIA SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_NEPALI_INDIA
#define SUBLANG_NEPALI_INDIA SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_NORWEGIAN_BOKMAL
#define SUBLANG_NORWEGIAN_BOKMAL SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_NORWEGIAN_NYNORSK
#define SUBLANG_NORWEGIAN_NYNORSK SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_PORTUGUESE
#define SUBLANG_PORTUGUESE SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_PORTUGUESE_BRAZILIAN
#define SUBLANG_PORTUGUESE_BRAZILIAN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SERBIAN_CYRILLIC
#define SUBLANG_SERBIAN_CYRILLIC SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SERBIAN_LATIN
#define SUBLANG_SERBIAN_LATIN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SPANISH
#define SUBLANG_SPANISH SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SPANISH_ARGENTINA
#define SUBLANG_SPANISH_ARGENTINA SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SPANISH_BOLIVIA
#define SUBLANG_SPANISH_BOLIVIA SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SPANISH_CHILE
#define SUBLANG_SPANISH_CHILE SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SPANISH_COLOMBIA
#define SUBLANG_SPANISH_COLOMBIA SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SPANISH_COSTA_RICA
#define SUBLANG_SPANISH_COSTA_RICA SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SPANISH_DOMINICAN_REPUBLIC
#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SPANISH_ECUADOR
#define SUBLANG_SPANISH_ECUADOR SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SPANISH_EL_SALVADOR
#define SUBLANG_SPANISH_EL_SALVADOR SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SPANISH_GUATEMALA
#define SUBLANG_SPANISH_GUATEMALA SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SPANISH_HONDURAS
#define SUBLANG_SPANISH_HONDURAS SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SPANISH_MEXICAN
#define SUBLANG_SPANISH_MEXICAN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SPANISH_MODERN
#define SUBLANG_SPANISH_MODERN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SPANISH_NICARAGUA
#define SUBLANG_SPANISH_NICARAGUA SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SPANISH_PANAMA
#define SUBLANG_SPANISH_PANAMA SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SPANISH_PARAGUAY
#define SUBLANG_SPANISH_PARAGUAY SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SPANISH_PERU
#define SUBLANG_SPANISH_PERU SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SPANISH_PUERTO_RICO
#define SUBLANG_SPANISH_PUERTO_RICO SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SPANISH_URUGUAY
#define SUBLANG_SPANISH_URUGUAY SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SPANISH_VENEZUELA
#define SUBLANG_SPANISH_VENEZUELA SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SWEDISH
#define SUBLANG_SWEDISH SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_SWEDISH_FINLAND
#define SUBLANG_SWEDISH_FINLAND SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_URDU_INDIA
#define SUBLANG_URDU_INDIA SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_URDU_PAKISTAN
#define SUBLANG_URDU_PAKISTAN SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_UZBEK_CYRILLIC
#define SUBLANG_UZBEK_CYRILLIC SUBLANG_DEFAULT
#endif
#ifndef SUBLANG_UZBEK_LATIN
#define SUBLANG_UZBEK_LATIN SUBLANG_DEFAULT
#endif


#endif

#define LNG(wxlang, canonical, winlang, winsublang, layout, desc) \
  info.Language = wxlang;                               \
  info.CanonicalName = wxT(canonical);                  \
  info.LayoutDirection = layout;                        \
  info.Description = wxT(desc);                         \
  SETWINLANG(info, winlang, winsublang)                 \
  AddLanguage(info);

void wxLocale::InitLanguagesDB() {
  wxLanguageInfo info;
  wxStringTokenizer tkn;
  LNG( wxLANGUAGE_ABKHAZIAN,                  "ab", 0, 0, wxLayout_LeftToRight, "Abkhazian" )
  LNG( wxLANGUAGE_AFAR,                       "aa", 0, 0, wxLayout_LeftToRight, "Afar" )
  LNG( wxLANGUAGE_AFRIKAANS,                  "af_ZA", LANG_AFRIKAANS, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Afrikaans" )
  LNG( wxLANGUAGE_ALBANIAN,                   "sq_AL", LANG_ALBANIAN, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Albanian" )
  LNG( wxLANGUAGE_AMHARIC,                    "am", 0, 0, wxLayout_LeftToRight, "Amharic" )
  LNG( wxLANGUAGE_ARABIC,                     "ar", LANG_ARABIC, SUBLANG_DEFAULT, wxLayout_RightToLeft, "Arabic" )
  LNG( wxLANGUAGE_ARABIC_ALGERIA,             "ar_DZ", LANG_ARABIC, SUBLANG_ARABIC_ALGERIA, wxLayout_RightToLeft, "Arabic (Algeria)" )
  LNG( wxLANGUAGE_ARABIC_BAHRAIN,             "ar_BH", LANG_ARABIC, SUBLANG_ARABIC_BAHRAIN, wxLayout_RightToLeft, "Arabic (Bahrain)" )
  LNG( wxLANGUAGE_ARABIC_EGYPT,               "ar_EG", LANG_ARABIC, SUBLANG_ARABIC_EGYPT, wxLayout_RightToLeft, "Arabic (Egypt)" )
  LNG( wxLANGUAGE_ARABIC_IRAQ,                "ar_IQ", LANG_ARABIC, SUBLANG_ARABIC_IRAQ, wxLayout_RightToLeft, "Arabic (Iraq)" )
  LNG( wxLANGUAGE_ARABIC_JORDAN,              "ar_JO", LANG_ARABIC, SUBLANG_ARABIC_JORDAN, wxLayout_RightToLeft, "Arabic (Jordan)" )
  LNG( wxLANGUAGE_ARABIC_KUWAIT,              "ar_KW", LANG_ARABIC, SUBLANG_ARABIC_KUWAIT, wxLayout_RightToLeft, "Arabic (Kuwait)" )
  LNG( wxLANGUAGE_ARABIC_LEBANON,             "ar_LB", LANG_ARABIC, SUBLANG_ARABIC_LEBANON, wxLayout_RightToLeft, "Arabic (Lebanon)" )
  LNG( wxLANGUAGE_ARABIC_LIBYA,               "ar_LY", LANG_ARABIC, SUBLANG_ARABIC_LIBYA, wxLayout_RightToLeft, "Arabic (Libya)" )
  LNG( wxLANGUAGE_ARABIC_MOROCCO,             "ar_MA", LANG_ARABIC, SUBLANG_ARABIC_MOROCCO, wxLayout_RightToLeft, "Arabic (Morocco)" )
  LNG( wxLANGUAGE_ARABIC_OMAN,                "ar_OM", LANG_ARABIC, SUBLANG_ARABIC_OMAN, wxLayout_RightToLeft, "Arabic (Oman)" )
  LNG( wxLANGUAGE_ARABIC_QATAR,               "ar_QA", LANG_ARABIC, SUBLANG_ARABIC_QATAR, wxLayout_RightToLeft, "Arabic (Qatar)" )
  LNG( wxLANGUAGE_ARABIC_SAUDI_ARABIA,        "ar_SA", LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA, wxLayout_RightToLeft, "Arabic (Saudi Arabia)" )
  LNG( wxLANGUAGE_ARABIC_SUDAN,               "ar_SD", 0, 0, wxLayout_RightToLeft, "Arabic (Sudan)" )
  LNG( wxLANGUAGE_ARABIC_SYRIA,               "ar_SY", LANG_ARABIC, SUBLANG_ARABIC_SYRIA, wxLayout_RightToLeft, "Arabic (Syria)" )
  LNG( wxLANGUAGE_ARABIC_TUNISIA,             "ar_TN", LANG_ARABIC, SUBLANG_ARABIC_TUNISIA, wxLayout_RightToLeft, "Arabic (Tunisia)" )
  LNG( wxLANGUAGE_ARABIC_UAE,                 "ar_AE", LANG_ARABIC, SUBLANG_ARABIC_UAE, wxLayout_RightToLeft, "Arabic (Uae)" )
  LNG( wxLANGUAGE_ARABIC_YEMEN,               "ar_YE", LANG_ARABIC, SUBLANG_ARABIC_YEMEN, wxLayout_RightToLeft, "Arabic (Yemen)" )
  LNG( wxLANGUAGE_ARMENIAN,                   "hy", LANG_ARMENIAN, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Armenian" )
  LNG( wxLANGUAGE_ASSAMESE,                   "as", LANG_ASSAMESE, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Assamese" )
  LNG( wxLANGUAGE_AYMARA,                     "ay", 0, 0, wxLayout_LeftToRight, "Aymara" )
  LNG( wxLANGUAGE_AZERI,                      "az", LANG_AZERI, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Azeri" )
  LNG( wxLANGUAGE_AZERI_CYRILLIC,             "az", LANG_AZERI, SUBLANG_AZERI_CYRILLIC, wxLayout_LeftToRight, "Azeri (Cyrillic)" )
  LNG( wxLANGUAGE_AZERI_LATIN,                "az", LANG_AZERI, SUBLANG_AZERI_LATIN, wxLayout_LeftToRight, "Azeri (Latin)" )
  LNG( wxLANGUAGE_BASHKIR,                    "ba", 0, 0, wxLayout_LeftToRight, "Bashkir" )
  LNG( wxLANGUAGE_BASQUE,                     "eu_ES", LANG_BASQUE, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Basque" )
  LNG( wxLANGUAGE_BELARUSIAN,                 "be_BY", LANG_BELARUSIAN, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Belarusian" )
  LNG( wxLANGUAGE_BENGALI,                    "bn", LANG_BENGALI, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Bengali" )
  LNG( wxLANGUAGE_BHUTANI,                    "dz", 0, 0, wxLayout_LeftToRight, "Bhutani" )
  LNG( wxLANGUAGE_BIHARI,                     "bh", 0, 0, wxLayout_LeftToRight, "Bihari" )
  LNG( wxLANGUAGE_BISLAMA,                    "bi", 0, 0, wxLayout_LeftToRight, "Bislama" )
  LNG( wxLANGUAGE_BRETON,                     "br", 0, 0, wxLayout_LeftToRight, "Breton" )
  LNG( wxLANGUAGE_BULGARIAN,                  "bg_BG", LANG_BULGARIAN, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Bulgarian" )
  LNG( wxLANGUAGE_BURMESE,                    "my", 0, 0, wxLayout_LeftToRight, "Burmese" )
  LNG( wxLANGUAGE_CAMBODIAN,                  "km", 0, 0, wxLayout_LeftToRight, "Cambodian" )
  LNG( wxLANGUAGE_CATALAN,                    "ca_ES", LANG_CATALAN, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Catalan" )
  LNG( wxLANGUAGE_CHINESE,                    "zh_TW", LANG_CHINESE, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Chinese" )
  LNG( wxLANGUAGE_CHINESE_SIMPLIFIED,         "zh_CN", LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED, wxLayout_LeftToRight, "Chinese (Simplified)" )
  LNG( wxLANGUAGE_CHINESE_TRADITIONAL,        "zh_TW", LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL, wxLayout_LeftToRight, "Chinese (Traditional)" )
  LNG( wxLANGUAGE_CHINESE_HONGKONG,           "zh_HK", LANG_CHINESE, SUBLANG_CHINESE_HONGKONG, wxLayout_LeftToRight, "Chinese (Hongkong)" )
  LNG( wxLANGUAGE_CHINESE_MACAU,              "zh_MO", LANG_CHINESE, SUBLANG_CHINESE_MACAU, wxLayout_LeftToRight, "Chinese (Macau)" )
  LNG( wxLANGUAGE_CHINESE_SINGAPORE,          "zh_SG", LANG_CHINESE, SUBLANG_CHINESE_SINGAPORE, wxLayout_LeftToRight, "Chinese (Singapore)" )
  LNG( wxLANGUAGE_CHINESE_TAIWAN,             "zh_TW", LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL, wxLayout_LeftToRight, "Chinese (Taiwan)" )
  LNG( wxLANGUAGE_CORSICAN,                   "co", 0, 0, wxLayout_LeftToRight, "Corsican" )
  LNG( wxLANGUAGE_CROATIAN,                   "hr_HR", LANG_CROATIAN, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Croatian" )
  LNG( wxLANGUAGE_CZECH,                      "cs_CZ", LANG_CZECH, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Czech" )
  LNG( wxLANGUAGE_DANISH,                     "da_DK", LANG_DANISH, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Danish" )
  LNG( wxLANGUAGE_DUTCH,                      "nl_NL", LANG_DUTCH, SUBLANG_DUTCH, wxLayout_LeftToRight, "Dutch" )
  LNG( wxLANGUAGE_DUTCH_BELGIAN,              "nl_BE", LANG_DUTCH, SUBLANG_DUTCH_BELGIAN, wxLayout_LeftToRight, "Dutch (Belgian)" )
  LNG( wxLANGUAGE_ENGLISH,                    "en_GB", LANG_ENGLISH, SUBLANG_ENGLISH_UK, wxLayout_LeftToRight, "English" )
  LNG( wxLANGUAGE_ENGLISH_UK,                 "en_GB", LANG_ENGLISH, SUBLANG_ENGLISH_UK, wxLayout_LeftToRight, "English (U.K.)" )
  LNG( wxLANGUAGE_ENGLISH_US,                 "en_US", LANG_ENGLISH, SUBLANG_ENGLISH_US, wxLayout_LeftToRight, "English (U.S.)" )
  LNG( wxLANGUAGE_ENGLISH_AUSTRALIA,          "en_AU", LANG_ENGLISH, SUBLANG_ENGLISH_AUS, wxLayout_LeftToRight, "English (Australia)" )
  LNG( wxLANGUAGE_ENGLISH_BELIZE,             "en_BZ", LANG_ENGLISH, SUBLANG_ENGLISH_BELIZE, wxLayout_LeftToRight, "English (Belize)" )
  LNG( wxLANGUAGE_ENGLISH_BOTSWANA,           "en_BW", 0, 0, wxLayout_LeftToRight, "English (Botswana)" )
  LNG( wxLANGUAGE_ENGLISH_CANADA,             "en_CA", LANG_ENGLISH, SUBLANG_ENGLISH_CAN, wxLayout_LeftToRight, "English (Canada)" )
  LNG( wxLANGUAGE_ENGLISH_CARIBBEAN,          "en_CB", LANG_ENGLISH, SUBLANG_ENGLISH_CARIBBEAN, wxLayout_LeftToRight, "English (Caribbean)" )
  LNG( wxLANGUAGE_ENGLISH_DENMARK,            "en_DK", 0, 0, wxLayout_LeftToRight, "English (Denmark)" )
  LNG( wxLANGUAGE_ENGLISH_EIRE,               "en_IE", LANG_ENGLISH, SUBLANG_ENGLISH_EIRE, wxLayout_LeftToRight, "English (Eire)" )
  LNG( wxLANGUAGE_ENGLISH_JAMAICA,            "en_JM", LANG_ENGLISH, SUBLANG_ENGLISH_JAMAICA, wxLayout_LeftToRight, "English (Jamaica)" )
  LNG( wxLANGUAGE_ENGLISH_NEW_ZEALAND,        "en_NZ", LANG_ENGLISH, SUBLANG_ENGLISH_NZ, wxLayout_LeftToRight, "English (New Zealand)" )
  LNG( wxLANGUAGE_ENGLISH_PHILIPPINES,        "en_PH", LANG_ENGLISH, SUBLANG_ENGLISH_PHILIPPINES, wxLayout_LeftToRight, "English (Philippines)" )
  LNG( wxLANGUAGE_ENGLISH_SOUTH_AFRICA,       "en_ZA", LANG_ENGLISH, SUBLANG_ENGLISH_SOUTH_AFRICA, wxLayout_LeftToRight, "English (South Africa)" )
  LNG( wxLANGUAGE_ENGLISH_TRINIDAD,           "en_TT", LANG_ENGLISH, SUBLANG_ENGLISH_TRINIDAD, wxLayout_LeftToRight, "English (Trinidad)" )
  LNG( wxLANGUAGE_ENGLISH_ZIMBABWE,           "en_ZW", LANG_ENGLISH, SUBLANG_ENGLISH_ZIMBABWE, wxLayout_LeftToRight, "English (Zimbabwe)" )
  LNG( wxLANGUAGE_ESPERANTO,                  "eo", 0, 0, wxLayout_LeftToRight, "Esperanto" )
  LNG( wxLANGUAGE_ESTONIAN,                   "et_EE", LANG_ESTONIAN, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Estonian" )
  LNG( wxLANGUAGE_FAEROESE,                   "fo_FO", LANG_FAEROESE, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Faeroese" )
  LNG( wxLANGUAGE_FARSI,                      "fa_IR", LANG_FARSI, SUBLANG_DEFAULT, wxLayout_RightToLeft, "Farsi" )
  LNG( wxLANGUAGE_FIJI,                       "fj", 0, 0, wxLayout_LeftToRight, "Fiji" )
  LNG( wxLANGUAGE_FINNISH,                    "fi_FI", LANG_FINNISH, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Finnish" )
  LNG( wxLANGUAGE_FRENCH,                     "fr_FR", LANG_FRENCH, SUBLANG_FRENCH, wxLayout_LeftToRight, "French" )
  LNG( wxLANGUAGE_FRENCH_BELGIAN,             "fr_BE", LANG_FRENCH, SUBLANG_FRENCH_BELGIAN, wxLayout_LeftToRight, "French (Belgian)" )
  LNG( wxLANGUAGE_FRENCH_CANADIAN,            "fr_CA", LANG_FRENCH, SUBLANG_FRENCH_CANADIAN, wxLayout_LeftToRight, "French (Canadian)" )
  LNG( wxLANGUAGE_FRENCH_LUXEMBOURG,          "fr_LU", LANG_FRENCH, SUBLANG_FRENCH_LUXEMBOURG, wxLayout_LeftToRight, "French (Luxembourg)" )
  LNG( wxLANGUAGE_FRENCH_MONACO,              "fr_MC", LANG_FRENCH, SUBLANG_FRENCH_MONACO, wxLayout_LeftToRight, "French (Monaco)" )
  LNG( wxLANGUAGE_FRENCH_SWISS,               "fr_CH", LANG_FRENCH, SUBLANG_FRENCH_SWISS, wxLayout_LeftToRight, "French (Swiss)" )
  LNG( wxLANGUAGE_FRISIAN,                    "fy", 0, 0, wxLayout_LeftToRight, "Frisian" )
  LNG( wxLANGUAGE_GALICIAN,                   "gl_ES", 0, 0, wxLayout_LeftToRight, "Galician" )
  LNG( wxLANGUAGE_GEORGIAN,                   "ka_GE", LANG_GEORGIAN, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Georgian" )
  LNG( wxLANGUAGE_GERMAN,                     "de_DE", LANG_GERMAN, SUBLANG_GERMAN, wxLayout_LeftToRight, "German" )
  LNG( wxLANGUAGE_GERMAN_AUSTRIAN,            "de_AT", LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN, wxLayout_LeftToRight, "German (Austrian)" )
  LNG( wxLANGUAGE_GERMAN_BELGIUM,             "de_BE", 0, 0, wxLayout_LeftToRight, "German (Belgium)" )
  LNG( wxLANGUAGE_GERMAN_LIECHTENSTEIN,       "de_LI", LANG_GERMAN, SUBLANG_GERMAN_LIECHTENSTEIN, wxLayout_LeftToRight, "German (Liechtenstein)" )
  LNG( wxLANGUAGE_GERMAN_LUXEMBOURG,          "de_LU", LANG_GERMAN, SUBLANG_GERMAN_LUXEMBOURG, wxLayout_LeftToRight, "German (Luxembourg)" )
  LNG( wxLANGUAGE_GERMAN_SWISS,               "de_CH", LANG_GERMAN, SUBLANG_GERMAN_SWISS, wxLayout_LeftToRight, "German (Swiss)" )
  LNG( wxLANGUAGE_GREEK,                      "el_GR", LANG_GREEK, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Greek" )
  LNG( wxLANGUAGE_GREENLANDIC,                "kl_GL", 0, 0, wxLayout_LeftToRight, "Greenlandic" )
  LNG( wxLANGUAGE_GUARANI,                    "gn", 0, 0, wxLayout_LeftToRight, "Guarani" )
  LNG( wxLANGUAGE_GUJARATI,                   "gu", LANG_GUJARATI, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Gujarati" )
  LNG( wxLANGUAGE_HAUSA,                      "ha", 0, 0, wxLayout_LeftToRight, "Hausa" )
  LNG( wxLANGUAGE_HEBREW,                     "he_IL", LANG_HEBREW, SUBLANG_DEFAULT, wxLayout_RightToLeft, "Hebrew" )
  LNG( wxLANGUAGE_HINDI,                      "hi_IN", LANG_HINDI, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Hindi" )
  LNG( wxLANGUAGE_HUNGARIAN,                  "hu_HU", LANG_HUNGARIAN, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Hungarian" )
  LNG( wxLANGUAGE_ICELANDIC,                  "is_IS", LANG_ICELANDIC, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Icelandic" )
  LNG( wxLANGUAGE_INDONESIAN,                 "id_ID", LANG_INDONESIAN, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Indonesian" )
  LNG( wxLANGUAGE_INTERLINGUA,                "ia", 0, 0, wxLayout_LeftToRight, "Interlingua" )
  LNG( wxLANGUAGE_INTERLINGUE,                "ie", 0, 0, wxLayout_LeftToRight, "Interlingue" )
  LNG( wxLANGUAGE_INUKTITUT,                  "iu", 0, 0, wxLayout_LeftToRight, "Inuktitut" )
  LNG( wxLANGUAGE_INUPIAK,                    "ik", 0, 0, wxLayout_LeftToRight, "Inupiak" )
  LNG( wxLANGUAGE_IRISH,                      "ga_IE", 0, 0, wxLayout_LeftToRight, "Irish" )
  LNG( wxLANGUAGE_ITALIAN,                    "it_IT", LANG_ITALIAN, SUBLANG_ITALIAN, wxLayout_LeftToRight, "Italian" )
  LNG( wxLANGUAGE_ITALIAN_SWISS,              "it_CH", LANG_ITALIAN, SUBLANG_ITALIAN_SWISS, wxLayout_LeftToRight, "Italian (Swiss)" )
  LNG( wxLANGUAGE_JAPANESE,                   "ja_JP", LANG_JAPANESE, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Japanese" )
  LNG( wxLANGUAGE_JAVANESE,                   "jw", 0, 0, wxLayout_LeftToRight, "Javanese" )
  LNG( wxLANGUAGE_KANNADA,                    "kn", LANG_KANNADA, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Kannada" )
  LNG( wxLANGUAGE_KASHMIRI,                   "ks", LANG_KASHMIRI, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Kashmiri" )
  LNG( wxLANGUAGE_KASHMIRI_INDIA,             "ks_IN", LANG_KASHMIRI, SUBLANG_KASHMIRI_INDIA, wxLayout_LeftToRight, "Kashmiri (India)" )
  LNG( wxLANGUAGE_KAZAKH,                     "kk", LANG_KAZAK, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Kazakh" )
  LNG( wxLANGUAGE_KERNEWEK,                   "kw_GB", 0, 0, wxLayout_LeftToRight, "Kernewek" )
  LNG( wxLANGUAGE_KINYARWANDA,                "rw", 0, 0, wxLayout_LeftToRight, "Kinyarwanda" )
  LNG( wxLANGUAGE_KIRGHIZ,                    "ky", 0, 0, wxLayout_LeftToRight, "Kirghiz" )
  LNG( wxLANGUAGE_KIRUNDI,                    "rn", 0, 0, wxLayout_LeftToRight, "Kirundi" )
  LNG( wxLANGUAGE_KONKANI,                    "", LANG_KONKANI, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Konkani" )
  LNG( wxLANGUAGE_KOREAN,                     "ko_KR", LANG_KOREAN, SUBLANG_KOREAN, wxLayout_LeftToRight, "Korean" )
  LNG( wxLANGUAGE_KURDISH,                    "ku_TR", 0, 0, wxLayout_LeftToRight, "Kurdish" )
  LNG( wxLANGUAGE_LAOTHIAN,                   "lo", 0, 0, wxLayout_LeftToRight, "Laothian" )
  LNG( wxLANGUAGE_LATIN,                      "la", 0, 0, wxLayout_LeftToRight, "Latin" )
  LNG( wxLANGUAGE_LATVIAN,                    "lv_LV", LANG_LATVIAN, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Latvian" )
  LNG( wxLANGUAGE_LINGALA,                    "ln", 0, 0, wxLayout_LeftToRight, "Lingala" )
  LNG( wxLANGUAGE_LITHUANIAN,                 "lt_LT", LANG_LITHUANIAN, SUBLANG_LITHUANIAN, wxLayout_LeftToRight, "Lithuanian" )
  LNG( wxLANGUAGE_MACEDONIAN,                 "mk_MK", LANG_MACEDONIAN, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Macedonian" )
  LNG( wxLANGUAGE_MALAGASY,                   "mg", 0, 0, wxLayout_LeftToRight, "Malagasy" )
  LNG( wxLANGUAGE_MALAY,                      "ms_MY", LANG_MALAY, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Malay" )
  LNG( wxLANGUAGE_MALAYALAM,                  "ml", LANG_MALAYALAM, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Malayalam" )
  LNG( wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM,    "ms_BN", LANG_MALAY, SUBLANG_MALAY_BRUNEI_DARUSSALAM, wxLayout_LeftToRight, "Malay (Brunei Darussalam)" )
  LNG( wxLANGUAGE_MALAY_MALAYSIA,             "ms_MY", LANG_MALAY, SUBLANG_MALAY_MALAYSIA, wxLayout_LeftToRight, "Malay (Malaysia)" )
  LNG( wxLANGUAGE_MALTESE,                    "mt_MT", 0, 0, wxLayout_LeftToRight, "Maltese" )
  LNG( wxLANGUAGE_MANIPURI,                   "", LANG_MANIPURI, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Manipuri" )
  LNG( wxLANGUAGE_MAORI,                      "mi", 0, 0, wxLayout_LeftToRight, "Maori" )
  LNG( wxLANGUAGE_MARATHI,                    "mr_IN", LANG_MARATHI, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Marathi" )
  LNG( wxLANGUAGE_MOLDAVIAN,                  "mo", 0, 0, wxLayout_LeftToRight, "Moldavian" )
  LNG( wxLANGUAGE_MONGOLIAN,                  "mn", 0, 0, wxLayout_LeftToRight, "Mongolian" )
  LNG( wxLANGUAGE_NAURU,                      "na", 0, 0, wxLayout_LeftToRight, "Nauru" )
  LNG( wxLANGUAGE_NEPALI,                     "ne_NP", LANG_NEPALI, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Nepali" )
  LNG( wxLANGUAGE_NEPALI_INDIA,               "ne_IN", LANG_NEPALI, SUBLANG_NEPALI_INDIA, wxLayout_LeftToRight, "Nepali (India)" )
  LNG( wxLANGUAGE_NORWEGIAN_BOKMAL,           "nb_NO", LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL, wxLayout_LeftToRight, "Norwegian (Bokmal)" )
  LNG( wxLANGUAGE_NORWEGIAN_NYNORSK,          "nn_NO", LANG_NORWEGIAN, SUBLANG_NORWEGIAN_NYNORSK, wxLayout_LeftToRight, "Norwegian (Nynorsk)" )
  LNG( wxLANGUAGE_OCCITAN,                    "oc", 0, 0, wxLayout_LeftToRight, "Occitan" )
  LNG( wxLANGUAGE_ORIYA,                      "or", LANG_ORIYA, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Oriya" )
  LNG( wxLANGUAGE_OROMO,                      "om", 0, 0, wxLayout_LeftToRight, "(Afan) Oromo" )
  LNG( wxLANGUAGE_PASHTO,                     "ps", 0, 0, wxLayout_LeftToRight, "Pashto, Pushto" )
  LNG( wxLANGUAGE_POLISH,                     "pl_PL", LANG_POLISH, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Polish" )
  LNG( wxLANGUAGE_PORTUGUESE,                 "pt_PT", LANG_PORTUGUESE, SUBLANG_PORTUGUESE, wxLayout_LeftToRight, "Portuguese" )
  LNG( wxLANGUAGE_PORTUGUESE_BRAZILIAN,       "pt_BR", LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN, wxLayout_LeftToRight, "Portuguese (Brazilian)" )
  LNG( wxLANGUAGE_PUNJABI,                    "pa", LANG_PUNJABI, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Punjabi" )
  LNG( wxLANGUAGE_QUECHUA,                    "qu", 0, 0, wxLayout_LeftToRight, "Quechua" )
  LNG( wxLANGUAGE_RHAETO_ROMANCE,             "rm", 0, 0, wxLayout_LeftToRight, "Rhaeto-Romance" )
  LNG( wxLANGUAGE_ROMANIAN,                   "ro_RO", LANG_ROMANIAN, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Romanian" )
  LNG( wxLANGUAGE_RUSSIAN,                    "ru_RU", LANG_RUSSIAN, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Russian" )
  LNG( wxLANGUAGE_RUSSIAN_UKRAINE,            "ru_UA", 0, 0, wxLayout_LeftToRight, "Russian (Ukraine)" )
  LNG( wxLANGUAGE_SAMI,                       "se_NO", LANG_SAMI, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Northern Sami" )
  LNG( wxLANGUAGE_SAMOAN,                     "sm", 0, 0, wxLayout_LeftToRight, "Samoan" )
  LNG( wxLANGUAGE_SANGHO,                     "sg", 0, 0, wxLayout_LeftToRight, "Sangho" )
  LNG( wxLANGUAGE_SANSKRIT,                   "sa", LANG_SANSKRIT, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Sanskrit" )
  LNG( wxLANGUAGE_SCOTS_GAELIC,               "gd", 0, 0, wxLayout_LeftToRight, "Scots Gaelic" )
  LNG( wxLANGUAGE_SERBIAN,                    "sr_RS", LANG_SERBIAN, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Serbian" )
  LNG( wxLANGUAGE_SERBIAN_CYRILLIC,           "sr_RS", LANG_SERBIAN, SUBLANG_SERBIAN_CYRILLIC, wxLayout_LeftToRight, "Serbian (Cyrillic)" )
  LNG( wxLANGUAGE_SERBIAN_LATIN,              "sr_RS@latin", LANG_SERBIAN, SUBLANG_SERBIAN_LATIN, wxLayout_LeftToRight, "Serbian (Latin)" )
  LNG( wxLANGUAGE_SERBIAN_CYRILLIC,           "sr_YU", LANG_SERBIAN, SUBLANG_SERBIAN_CYRILLIC, wxLayout_LeftToRight, "Serbian (Cyrillic)" )
  LNG( wxLANGUAGE_SERBIAN_LATIN,              "sr_YU@latin", LANG_SERBIAN, SUBLANG_SERBIAN_LATIN, wxLayout_LeftToRight, "Serbian (Latin)" )
  LNG( wxLANGUAGE_SERBO_CROATIAN,             "sh", 0, 0, wxLayout_LeftToRight, "Serbo-Croatian" )
  LNG( wxLANGUAGE_SESOTHO,                    "st", 0, 0, wxLayout_LeftToRight, "Sesotho" )
  LNG( wxLANGUAGE_SETSWANA,                   "tn", 0, 0, wxLayout_LeftToRight, "Setswana" )
  LNG( wxLANGUAGE_SHONA,                      "sn", 0, 0, wxLayout_LeftToRight, "Shona" )
  LNG( wxLANGUAGE_SINDHI,                     "sd", LANG_SINDHI, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Sindhi" )
  LNG( wxLANGUAGE_SINHALESE,                  "si", 0, 0, wxLayout_LeftToRight, "Sinhalese" )
  LNG( wxLANGUAGE_SISWATI,                    "ss", 0, 0, wxLayout_LeftToRight, "Siswati" )
  LNG( wxLANGUAGE_SLOVAK,                     "sk_SK", LANG_SLOVAK, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Slovak" )
  LNG( wxLANGUAGE_SLOVENIAN,                  "sl_SI", LANG_SLOVENIAN, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Slovenian" )
  LNG( wxLANGUAGE_SOMALI,                     "so", 0, 0, wxLayout_LeftToRight, "Somali" )
  LNG( wxLANGUAGE_SPANISH,                    "es_ES", LANG_SPANISH, SUBLANG_SPANISH, wxLayout_LeftToRight, "Spanish" )
  LNG( wxLANGUAGE_SPANISH_ARGENTINA,          "es_AR", LANG_SPANISH, SUBLANG_SPANISH_ARGENTINA, wxLayout_LeftToRight, "Spanish (Argentina)" )
  LNG( wxLANGUAGE_SPANISH_BOLIVIA,            "es_BO", LANG_SPANISH, SUBLANG_SPANISH_BOLIVIA, wxLayout_LeftToRight, "Spanish (Bolivia)" )
  LNG( wxLANGUAGE_SPANISH_CHILE,              "es_CL", LANG_SPANISH, SUBLANG_SPANISH_CHILE, wxLayout_LeftToRight, "Spanish (Chile)" )
  LNG( wxLANGUAGE_SPANISH_COLOMBIA,           "es_CO", LANG_SPANISH, SUBLANG_SPANISH_COLOMBIA, wxLayout_LeftToRight, "Spanish (Colombia)" )
  LNG( wxLANGUAGE_SPANISH_COSTA_RICA,         "es_CR", LANG_SPANISH, SUBLANG_SPANISH_COSTA_RICA, wxLayout_LeftToRight, "Spanish (Costa Rica)" )
  LNG( wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC, "es_DO", LANG_SPANISH, SUBLANG_SPANISH_DOMINICAN_REPUBLIC, wxLayout_LeftToRight, "Spanish (Dominican republic)" )
  LNG( wxLANGUAGE_SPANISH_ECUADOR,            "es_EC", LANG_SPANISH, SUBLANG_SPANISH_ECUADOR, wxLayout_LeftToRight, "Spanish (Ecuador)" )
  LNG( wxLANGUAGE_SPANISH_EL_SALVADOR,        "es_SV", LANG_SPANISH, SUBLANG_SPANISH_EL_SALVADOR, wxLayout_LeftToRight, "Spanish (El Salvador)" )
  LNG( wxLANGUAGE_SPANISH_GUATEMALA,          "es_GT", LANG_SPANISH, SUBLANG_SPANISH_GUATEMALA, wxLayout_LeftToRight, "Spanish (Guatemala)" )
  LNG( wxLANGUAGE_SPANISH_HONDURAS,           "es_HN", LANG_SPANISH, SUBLANG_SPANISH_HONDURAS, wxLayout_LeftToRight, "Spanish (Honduras)" )
  LNG( wxLANGUAGE_SPANISH_MEXICAN,            "es_MX", LANG_SPANISH, SUBLANG_SPANISH_MEXICAN, wxLayout_LeftToRight, "Spanish (Mexican)" )
  LNG( wxLANGUAGE_SPANISH_MODERN,             "es_ES", LANG_SPANISH, SUBLANG_SPANISH_MODERN, wxLayout_LeftToRight, "Spanish (Modern)" )
  LNG( wxLANGUAGE_SPANISH_NICARAGUA,          "es_NI", LANG_SPANISH, SUBLANG_SPANISH_NICARAGUA, wxLayout_LeftToRight, "Spanish (Nicaragua)" )
  LNG( wxLANGUAGE_SPANISH_PANAMA,             "es_PA", LANG_SPANISH, SUBLANG_SPANISH_PANAMA, wxLayout_LeftToRight, "Spanish (Panama)" )
  LNG( wxLANGUAGE_SPANISH_PARAGUAY,           "es_PY", LANG_SPANISH, SUBLANG_SPANISH_PARAGUAY, wxLayout_LeftToRight, "Spanish (Paraguay)" )
  LNG( wxLANGUAGE_SPANISH_PERU,               "es_PE", LANG_SPANISH, SUBLANG_SPANISH_PERU, wxLayout_LeftToRight, "Spanish (Peru)" )
  LNG( wxLANGUAGE_SPANISH_PUERTO_RICO,        "es_PR", LANG_SPANISH, SUBLANG_SPANISH_PUERTO_RICO, wxLayout_LeftToRight, "Spanish (Puerto Rico)" )
  LNG( wxLANGUAGE_SPANISH_URUGUAY,            "es_UY", LANG_SPANISH, SUBLANG_SPANISH_URUGUAY, wxLayout_LeftToRight, "Spanish (Uruguay)" )
  LNG( wxLANGUAGE_SPANISH_US,                 "es_US", 0, 0, wxLayout_LeftToRight, "Spanish (U.S.)" )
  LNG( wxLANGUAGE_SPANISH_VENEZUELA,          "es_VE", LANG_SPANISH, SUBLANG_SPANISH_VENEZUELA, wxLayout_LeftToRight, "Spanish (Venezuela)" )
  LNG( wxLANGUAGE_SUNDANESE,                  "su", 0, 0, wxLayout_LeftToRight, "Sundanese" )
  LNG( wxLANGUAGE_SWAHILI,                    "sw_KE", LANG_SWAHILI, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Swahili" )
  LNG( wxLANGUAGE_SWEDISH,                    "sv_SE", LANG_SWEDISH, SUBLANG_SWEDISH, wxLayout_LeftToRight, "Swedish" )
  LNG( wxLANGUAGE_SWEDISH_FINLAND,            "sv_FI", LANG_SWEDISH, SUBLANG_SWEDISH_FINLAND, wxLayout_LeftToRight, "Swedish (Finland)" )
  LNG( wxLANGUAGE_TAGALOG,                    "tl_PH", 0, 0, wxLayout_LeftToRight, "Tagalog" )
  LNG( wxLANGUAGE_TAJIK,                      "tg", 0, 0, wxLayout_LeftToRight, "Tajik" )
  LNG( wxLANGUAGE_TAMIL,                      "ta", LANG_TAMIL, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Tamil" )
  LNG( wxLANGUAGE_TATAR,                      "tt", LANG_TATAR, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Tatar" )
  LNG( wxLANGUAGE_TELUGU,                     "te", LANG_TELUGU, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Telugu" )
  LNG( wxLANGUAGE_THAI,                       "th_TH", LANG_THAI, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Thai" )
  LNG( wxLANGUAGE_TIBETAN,                    "bo", 0, 0, wxLayout_LeftToRight, "Tibetan" )
  LNG( wxLANGUAGE_TIGRINYA,                   "ti", 0, 0, wxLayout_LeftToRight, "Tigrinya" )
  LNG( wxLANGUAGE_TONGA,                      "to", 0, 0, wxLayout_LeftToRight, "Tonga" )
  LNG( wxLANGUAGE_TSONGA,                     "ts", 0, 0, wxLayout_LeftToRight, "Tsonga" )
  LNG( wxLANGUAGE_TURKISH,                    "tr_TR", LANG_TURKISH, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Turkish" )
  LNG( wxLANGUAGE_TURKMEN,                    "tk", 0, 0, wxLayout_LeftToRight, "Turkmen" )
  LNG( wxLANGUAGE_TWI,                        "tw", 0, 0, wxLayout_LeftToRight, "Twi" )
  LNG( wxLANGUAGE_UIGHUR,                     "ug", 0, 0, wxLayout_LeftToRight, "Uighur" )
  LNG( wxLANGUAGE_UKRAINIAN,                  "uk_UA", LANG_UKRAINIAN, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Ukrainian" )
  LNG( wxLANGUAGE_URDU,                       "ur", LANG_URDU, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Urdu" )
  LNG( wxLANGUAGE_URDU_INDIA,                 "ur_IN", LANG_URDU, SUBLANG_URDU_INDIA, wxLayout_LeftToRight, "Urdu (India)" )
  LNG( wxLANGUAGE_URDU_PAKISTAN,              "ur_PK", LANG_URDU, SUBLANG_URDU_PAKISTAN, wxLayout_LeftToRight, "Urdu (Pakistan)" )
  LNG( wxLANGUAGE_UZBEK,                      "uz", LANG_UZBEK, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Uzbek" )
  LNG( wxLANGUAGE_UZBEK_CYRILLIC,             "uz", LANG_UZBEK, SUBLANG_UZBEK_CYRILLIC, wxLayout_LeftToRight, "Uzbek (Cyrillic)" )
  LNG( wxLANGUAGE_UZBEK_LATIN,                "uz", LANG_UZBEK, SUBLANG_UZBEK_LATIN, wxLayout_LeftToRight, "Uzbek (Latin)" )
  LNG( wxLANGUAGE_VALENCIAN,                  "ca_ES@valencia", LANG_VALENCIAN, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Valencian" )
  LNG( wxLANGUAGE_VIETNAMESE,                 "vi_VN", LANG_VIETNAMESE, SUBLANG_DEFAULT, wxLayout_LeftToRight, "Vietnamese" )
  LNG( wxLANGUAGE_VOLAPUK,                    "vo", 0, 0, wxLayout_LeftToRight, "Volapuk" )
  LNG( wxLANGUAGE_WELSH,                      "cy", 0, 0, wxLayout_LeftToRight, "Welsh" )
  LNG( wxLANGUAGE_WOLOF,                      "wo", 0, 0, wxLayout_LeftToRight, "Wolof" )
  LNG( wxLANGUAGE_XHOSA,                      "xh", 0, 0, wxLayout_LeftToRight, "Xhosa" )
  LNG( wxLANGUAGE_YIDDISH,                    "yi", 0, 0, wxLayout_LeftToRight, "Yiddish" )
  LNG( wxLANGUAGE_YORUBA,                     "yo", 0, 0, wxLayout_LeftToRight, "Yoruba" )
  LNG( wxLANGUAGE_ZHUANG,                     "za", 0, 0, wxLayout_LeftToRight, "Zhuang" )
  LNG( wxLANGUAGE_ZULU,                       "zu", 0, 0, wxLayout_LeftToRight, "Zulu" )
}
#undef LNG
